Git/Version imprimable
Une version à jour et éditable de ce livre est disponible sur Wikilivres,
une bibliothèque de livres pédagogiques, à l'URL :
https://fr.wikibooks.org/wiki/Git
Principes
Git est un logiciel de gestion de versions parmi les plus populaires. Il a été conçu pour gérer les projets de très grande envergure.
C'est un logiciel libre créé par Linus Torvalds qui a souhaité remplacer l'outil propriétaire qui était utilisé pour le développement du noyau Linux.
Git respecte les principes typiques Unix. Ce n'est pas un logiciel monolithique mais un ensemble de petits composants exécutant chacun une tâche unique. Par exemple dans Git v1.5.3, la suite d'utilitaires est constituée de 143 commandes spécialisées, dont une bonne fraction doit être appelée en Bash.
Ce logiciel en ligne de commande est disponible sur les Unix-like, Mac OS et Windows et est distribué selon les termes de la licence publique générale GNU version 2.
L'objectif du présent livre est de permettre au lecteur de se familiariser avec les concepts fondamentaux de Git et de prendre en main git afin de pouvoir gérer un projet de développement logiciel de façon décentralisée, de façon sûre et respectueuse des bonnes pratiques de développement.
Git est un logiciel de gestion de versions décentralisé (ou DVCS), c'est-à-dire qu'il n'y a pas de serveur central, chaque client a un dépôt complet en local, ainsi que l'historique intégral du projet.
Dans Git, tout tourne autour des versions et non pas des fichiers. Alors que dans les autres SCM, on gère des fichiers et les modifications effectuées sur ces fichiers au cours du temps, dans Git, les données sont gérées comme des flux d’instantanés du contenu de l'espace de travail.
Les principales commandes et différents types de dépôt Git sont résumés dans le schéma suivant :
Avant de commencer
Cette première étape est incontournable, nous allons voir comment installer et configurer Git sur votre machine. Suivez les instructions selon votre environnement de travail.
Il est à noter que l'architecture étant décentralisée, ces installations peuvent jouer le rôle du client ou du serveur, qui utilise le port 9418 mais passe en réseau par les services qui écoutent au port 22 (SSH), 80 (HTTP) ou 433 (HTTPS).
Installation
[modifier | modifier le wikicode]Linux
[modifier | modifier le wikicode]Sur la plupart des distributions, vous pouvez utiliser votre gestionnaire de paquet.
Vous pouvez aussi installer git depuis les sources.
Mac OS
[modifier | modifier le wikicode]Une installateur graphique est disponible sur Google. Sinon avec MacPorts lancer :
sudo port install git-core
Windows
[modifier | modifier le wikicode]Git pour Windows est téléchargeable sous forme de binaires précompilés sur msysGit ou encore Git Bash. Cela inclut l’utilitaire en lignes de commande, une interface graphique, et un client SSH.
De plus, le setup Cygwin le propose également.
Intégré dans un IDE
[modifier | modifier le wikicode]Plusieurs environnements de développement intégré incluent déjà des clients Git complets, comme NetBeans ou PhpStorm.
Configuration minimaliste de l'environnement
[modifier | modifier le wikicode]Avant d'aller plus loin, il est indispensable de configurer Git a minima.
Dans Git, les contributeurs à un projet sont identifiés par leur nom et leur adresse courriel, il faut donc fournir à Git ces deux informations.
git config --global user.email "michel.boudran@fr.wikibooks.org"
git config --global user.name "Michel Boudran"
Pour voir la configuration :
git config -l
Éviter de retaper son mot de passe
[modifier | modifier le wikicode]Git propose un mécanisme pour stocker temporairement votre mot de passe en mémoire et ainsi vous éviter d'avoir à le retaper à chaque push, pull ou toute opération impliquant un repo distant.
git config --global credential.helper cache
Si cela ne fonctionne pas après l'avoir retapé au moins une fois sur Linux, compléter le fichier suivant :
vim ~/.netrc
En ajoutant le nom du serveur. Exemple :
machine bitbucket.org
login <user>
password <password>
machine github.com
login <user>
password <password>
machine gitlab.com
login <user>
password <password>
Depuis septembre 2021, GitHub n'accepte plus les mots de passe mais demande à la place un token généré sur https://github.com/settings/tokens.
Si cela ne fonctionne toujours pas, vérifier que vous êtes dans le répertoire racine du projet, et que votre fichier .git/config est de la forme :
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = https://github.com/JackPotte/JackBot.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
Obtenir de l'aide
[modifier | modifier le wikicode]Git gère très bien l'auto-complétion. Au fur et à mesure que vous saisissez vos commandes, utilisez la touche tabulation ↹ pour que git vous propose des options.
À tout moment vous pouvez consulter le manuel de git avec
git --help
Pour obtenir de l'aide sur une commande en particulier, utilisez (exemple pour la commande branch
)
git branch --help
Lorsque vous lisez des documentations, vérifiez qu'elles s'appliquent bien à la version que vous utilisez :
git --version
Création de votre dépôt local
Maintenant que Git est installé, nous allons voir comment créer un dépôt sur notre machine. Un dépôt Git correspond à un projet de développement logiciel : chaque logiciel peut avoir un dépôt Git qui lui est réservé.
Nous allons voir trois cas d'utilisation différents :
- La création d'un dépôt git pour démarrer un projet vierge
- La création d'un dépôt git pour un projet existant, les fichiers se trouvant sur votre machine
- La création d'un dépôt afin de travailler sur un projet existant qui est déjà dans un dépôt git distant, c'est le cas le plus courant.
Création d'un dépôt git pour démarrer un projet vierge
[modifier | modifier le wikicode]Rendez-vous dans le répertoire dans lequel vous souhaitez créer votre dépôt (dans notre exemple, nous avons utilisé le répertoire temporaire cd /tmp
), puis
git init mon-projet
Initialized empty Git repository in /tmp/mon-projet/.git/
Vous pouvez ensuite vous placer dans le dossier "mon-projet" et travailler avec git.
Création d'un dépôt git avec une base de code existante
[modifier | modifier le wikicode]C'est tout aussi simple. Il faut d'abord se rendre dans le répertoire où se trouvent les sources et faire un git init
cd mon-projet git init
Initialized empty Git repository in /tmp/mon-projet/.git/
Dès lors, vous êtes prêt à travailler avec git dans ce répertoire.
Création d'une copie locale d'un dépôt distant (clone)
[modifier | modifier le wikicode]Cette fois-ci, les sources ne sont pas sur notre machine mais sur un dépôt distant qui existe déjà. C'est le cas d'utilisation le plus typique, vous souhaitez rejoindre un projet pour développer des fonctionnalités, corriger des anomalies et publier vos modifications. Pour cela, vous aurez besoin de l'adresse du dépôt distant.
Contrairement à ce qu'on a vu plus haut, nous n'allons pas utiliser init
mais clone
en se plaçant dans le répertoire dans lequel on souhaite placer son dépôt.
Lorsque vous faites un clone
, vous copiez l'intégralité du dépôt, il est donc normal que cette opération prenne longtemps pour les projets qui ont un long historique de contribution. Par exemple, pour le dépôt officiel du logiciel MediaWiki (git clone https://git.wikimedia.org/git/mediawiki/core.git
), il faudra télécharger pas moins de 200 Mo.
Dans notre exemple (toujours en travaillant dans le répertoire temporaire /tmp
), nous allons nous créer une copie locale d'un dépôt officiel qui représente un exemple d'extension MediaWiki :
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
Cloning into 'examples'... remote: Total 398 (delta 0), reused 398 (delta 0) Receiving objects: 100% (398/398), 52.19 KiB | 0 bytes/s, done. Resolving deltas: 100% (236/236), done. Checking connectivity... done
cd examples ls
chris_file chris_pushed_this_file_without_review ContentAction ErrorPage Example FourFileTemplate HelloWorld Parser_function.i18n.magic.php Parser_function.php Parser_hook.php Someone_was_here SpecialIncludable.php test1.php Variable_hook.i18n.magic.php Variable_hook.php
Si le dépôt cloné appartient à un tiers, il se peut que l'on ne puisse pas lui soumettre directement une version. Il faut en passer par une pull-request pour que la modification soit relue par le mainteneur.
Si le dépôt cloné demande une authentification forte, il faut créer une clé SSH et l'ajouter sur la forge.
Cloner une seule branche
[modifier | modifier le wikicode]git clone --single-branch --branch 1234-branche-test https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
Cloner un dépôt privé
[modifier | modifier le wikicode]Il faut spécifier en plus son login dans la commande, suivi d'un arobase, et elle demandera le mot de passe :
git clone https://jackpotte@gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
Créer un fork
[modifier | modifier le wikicode]Il est possible de créer un fork (aka bifurcation), c'est-à-dire une copie d'un dépôt dans un autre (historique inclus) en changeant l'URL du dépôt cloné[1] :
git remote set-url origin mon_depot_fork
Puis vérifier :
git remote -v
Pour synchroniser le fork avec sa source :
git merge upstream/master
Sinon on ne veut pas tout synchroniser, on peut faire un cherry-pick.
Références
[modifier | modifier le wikicode]
Visualiser le contenu de votre dépôt local
Avant de commencer à travailler vraiment sur le projet, nous allons déjà voir comment connaître l'état de notre dépôt.
Un dépôt est complexe, entre les commits, les branches, les tags, l'espace, les dépôts distants, le HEAD, le stash... Il est impératif de savoir comment, à tout moment, savoir où Git en est.
Dans ce chapitre, nous allons voir les différents outils qui sont à votre disposition pour comprendre dans quel état est votre dépôt local. Pour expérimenter les exemples que nous donnons, nous vous recommandons de travailler sur une copie d'un dépôt distant qui a déjà un historique fourni. En effet, ça sera bien plus représentatif qu'avec un dépôt vide où à peine créé.
Nous allons travailler suite à un
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
git log
[modifier | modifier le wikicode]Git log est la principale commande à connaître. Commençons par son utilisation la plus simple
git log
commit a59a042e1a7f1474a11c0bd2585ab2eb71b85c47 Merge: 5c511f2 12c8449 Author: Darkdadaah <example@yahoo.fr> Date: Sat May 25 08:49:21 2013 +0000 Merge "TEST 1" commit 12c84495c13b7bbf10f7d85fd9d9d2cb129a7952 Author: jackpotte <example@gmail.com> Date: Sat May 25 10:31:05 2013 +0200 TEST 1 Hackathon test. Change-Id: I079fe9c5ef6eee1e2e12a653bbb5cec474d28ec0 commit 5c511f28b89ee2a9cc46707802668b01bf54dec0 Author: Darkdadaah <example@yahoo.fr> Date: Sat May 25 10:19:44 2013 +0200 New file to "leave a trace" Change-Id: I5de6da00ad9712599e21ff630eee7d72d7177772 commit 27f4317fa4c325c98404e3cc8d443a164279b041 Author: Udit Saxena <example2@gmail.com> Date: Mon Apr 1 23:10:47 2013 +0530 Second try. Now third. Change-Id: Ic7cddbf04394c08bfe5cd240bf48e3641e7feaa5
Par défaut, git utilise less
pour vous permettre d'afficher les logs pages par pages. Ici, nous voyons 4 commits faits par 4 contributeurs différents. L'historique s'affiche dans l'ordre chronologique inversé : les modifications récentes sont au dessus des modifications anciennes.
Essayez d'ajouter de la couleur avec
git log --color
Vous pouvez voir l'historique des branches et des fusions avec
git log --graph
Vous pouvez voir l'historique en version réduite (une ligne par commit)
git log --oneline
Nous verrons plus tard comment utiliser log pour obtenir les informations qu'on souhaite. N'hésitez pas à combiner les options.
git log --oneline --graph --color
* 0eccb68 Increased version number * fc5fdf8 Working on http://www.mediawiki.org/wiki/Git/Tutorial Doing an unimportant commit And an unimportant amendment Change-Id: I5a8a912234ea1dae6adae5a13717faafab707a76 * 62505b3 Merge "Word-wrapped and punctuated comments." |\ | * 563788d Word-wrapped and punctuated comments. * | 506432a So simple if you have a tutorial and someone who shows you how it works and what you shouldn't forget |/ * 6609666 Merge "Implemented the getVersion function" |\ | * b1f8deb Implemented the getVersion function * | 70e59e5 Merge "Revert "Added a get version method"" |\ \ | * | 36af5f2 Revert "Added a get version method" * | | 14b21cf Merge "Change README to split the lines in more logical places" |\ \ \ | * | | 4090572 Change README to split the lines in more logical places | | |/ | |/| * | | 93ecbf0 Merge "removed a white space trailing the comment" |\ \ \ | * | | 4d3d534 removed a white space trailing the comment | |/ /
Afficher le résumé du dernier commit
[modifier | modifier le wikicode]git log -1
Afficher les résumés des commits du dossier courant
[modifier | modifier le wikicode]git log .
Rechercher une branche depuis un commit
[modifier | modifier le wikicode]Pour retracer l'historique des évènements il est parfois nécessaire de retrouver la branche (et la pull request) qui contenait un code. Or, l'historique (git blame
) ne contient que des commits.
Pour recherche la pull request qui contenait un commit donné (ex : 0eccb68) :
git log --merges --ancestry-path --oneline 0eccb68..master | grep 'pull request' | tail -n1 | awk '{ print $5 }';
Pour obtenir le nombre de lignes ajoutées et supprimées d'un contributeur donné[1] :
git log --author="mon_nom" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -
Rechercher un fichier supprimé
[modifier | modifier le wikicode]git log --diff-filter=D --summary | grep delete |grep nom_du_fichier
Rechercher une chaine de caractères ajoutée ou supprimée dans tous les diffs
[modifier | modifier le wikicode]git log -Sma_chaine
git gui
[modifier | modifier le wikicode]Il existe une extension git qui vous permet de visualiser votre dépôt local à l'aide d'un outil graphique. La plupart du temps, cette extension doit être installée en plus de git.
git gui
Une fenêtre s'ouvre, elle présente peu d'informations car nous n'avons pas encore de modifications à publier.
Ouvrez le menu « Dépôt » puis sélectionnez « Voir l'historique de toutes les branches ».
La fenêtre qui s'ouvre nous donne l'arborescence graphique qui nous permet de voir, dans l'ordre chronologique, toutes les modifications qui ont été faites.
gitweb
[modifier | modifier le wikicode]Gitweb est l'interface web officielle intégrée dans git. Elle permet de visualiser le contenu d'un dépôt git depuis tout navigateur web.
git instaweb
Votre navigateur devrait s'ouvrir automatiquement à l'adresse http://127.0.0.1:1234
Références
[modifier | modifier le wikicode]
Premiers pas
Préalable
[modifier | modifier le wikicode]Nous allons maintenant entrer dans le vif du sujet et faire une première modification dans le code source d'une application.
Cette première expérience va nous permettre de découvrir plusieurs notions importantes : l'espace de travail et l'index.
On reprend l'exemple précédent.
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
cd examples
Faisons d'abord un
git branch
qui va nous répondre
* master
Git nous indique qu'il existe une seule branche appelée master
et que c'est sur cette branche que nous travaillons comme l'indique l'astérisque en face de master
.
Cela nous est confirmé par
git status
qui nous répond
# On branch master nothing to commit, working directory clean
Vous pouvez faire un
git log
Pour voir quel est l'auteur et la date de la dernière modification : cela nous servira de repère pour la suite.
Ajouter un fichier dans la zone de transit
[modifier | modifier le wikicode]Commençons par une modification simple : l'ajout d'un fichier dans la staging area (la zone de transit vers la sauvegarde). Cela peut être une première étape si vous avez créer un dépôt vide.
Par exemple, créons un fichier mon_nouveau_fichier.txt
avec un petit texte dedans.
echo "Ceci est un test de git" > mon_nouveau_fichier.txt
Voyons la façon dont git perçoit ce nouveau fichier
git status
# On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # mon_nouveau_fichier.txt nothing added to commit but untracked files present (use "git add" to track)
Il nous indique qu'on est toujours sur la branche master
, qu'il y a un fichier mon_nouveau_fichier.txt
mais qu'il n'est pas suivi (« untracked ») par git.
Comme nous voulons intégrer ce fichier au projet, on ne peut pas encore faire le commit
, car commit
n'envoie que les fichiers qui sont *tracked*, c'est à dire dans l'index (*staging*). Ajoutons le fichier, comme git nous le suggère, avec add
git add mon_nouveau_fichier.txt
On refait un
git status
Et, cette fois, git nous répond
# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: mon_nouveau_fichier.txt #
Le fichier mon_nouveau_fichier.txt
sera bien intégré dans notre prochain commit
. Allons-y :
git commit -m "mon premier commit"
Remarquons ici qu'avec -m
, nous avons choisi de préciser le message de commit directement sur la ligne de commande. En lançant git commit
tout court, l'éditeur de texte ($EDITOR
) s'ouvre automatiquement pour inviter à saisir un commentaire de soumission.
[master 17eaa3e] mon premier commit 1 file changed, 1 insertion(+) create mode 100644 mon_nouveau_fichier.txt
Constatons immédiatement l'effet de ce commit :
git log
Notre dernier commit apparaît, en premier de la liste (c'est le plus récent).
commit 17eaa3e060b29d708a87867dcb725b7ec64ffaeb Author: Michel Boudran <michel.boudran@fr.wikibooks.org> Date: Tue Jul 22 22:00:39 2014 +0200 mon premier commit
Avec
git log --graph
On voit clairement que notre commit est lié au commit précédent.
Modifier un fichier
[modifier | modifier le wikicode]Faisons une autre modification. Par exemple, modifions le fichier mon_nouveau_fichier.txt
en ajoutant une ligne.
echo "Une seconde ligne pour un second test de git" >> mon_nouveau_fichier.txt
Voyons ce que git nous dit :
git status
# On branch master # Your branch is ahead of 'origin/master' by 1 commit. # (use "git push" to publish your local commits) # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: mon_nouveau_fichier.txt # no changes added to commit (use "git add" and/or "git commit -a")
diff
[modifier | modifier le wikicode]Git nous indique bien que le fichier a été modifié, voyons le résumé de ces modifications telles qu'elles sont perçues par git :
git diff
diff --git a/mon_nouveau_fichier.txt b/mon_nouveau_fichier.txt index a031263..762359c 100644 --- a/mon_nouveau_fichier.txt +++ b/mon_nouveau_fichier.txt @@ -1 +1,2 @@ Ceci est un test de git +Une seconde ligne pour un second test de git
Git nous montre la ligne qui a été ajoutée (le « + » en début de ligne).
Pour comparer une branche distante avec une locale, utiliser ".." :
git diff origin/master..master
sinon :
git diff master origin/master
add
[modifier | modifier le wikicode]On va maintenant faire le commit. Comme précédemment, il faut ajouter le fichier au *staging* :
git add mon_nouveau_fichier.txt
Si vous voulez ajouter au staging tous les changements qui ont été effectués (fichiers ajoutés, modifiés, supprimés), il vous suffit de faire[1]
git add --all
ou
git add -A
// ou
git add .
git status
# On branch master # Your branch is ahead of 'origin/master' by 1 commit. # (use "git push" to publish your local commits) # # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: mon_nouveau_fichier.txt #
commit
[modifier | modifier le wikicode]git commit -m "ma première modification"
[master 5556307] ma première modification 1 file changed, 1 insertion(+)
Remarquez le code « 5556307 » : il s'agit d'une abréviation de l'identifiant unique de l'objet Git (en l'occurrence une soumission). Chaque objet est haché en SHA-1. L'identifiant complet est en fait 5556307824d8d0425b38c9da696b84430e30f09f
, mais généralement les huit premiers caractères suffisent à l'identifier à coup sûr.
git log --graph
* commit 5556307824d8d0425b38c9da696b84430e30f09f | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 22:18:08 2014 +0200 | | ma première modification | * commit 17eaa3e060b29d708a87867dcb725b7ec64ffaeb | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 22:00:39 2014 +0200 | | mon premier commit |
On voit bien que nos deux commits se succèdent.
Supprimer un fichier
[modifier | modifier le wikicode]git rm mon_nouveau_fichier.txt
git status
# On branch master # Your branch is ahead of 'origin/master' by 2 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: mon_nouveau_fichier.txt #
Il n'est pas nécessaire de faire un add.
git commit -m "ma première suppression de fichier"
[master 77ea581] ma première suppression de fichier 1 file changed, 2 deletions(-) delete mode 100644 mon_nouveau_fichier.txt
Annuler une suppression
[modifier | modifier le wikicode]Certains outils comme PyCharm sont dotés d'un historique local (en plus de celui de Git) qui permet d'annuler un "git rm". Il est accessible via un clic droit sur le dossier à restaurer.
Regrouper des modifications
[modifier | modifier le wikicode]Il est possible de fusionner une soumission avec la dernière révision, via l'argument amend, sans avoir à réécrire leur résumé avec no-edit :
git commit --amend --no-edit
Généralement on l'utilise pour mettre à jour un commit :
git add -A && git commit --amend --no-edit && git push -f
Si la cible n'est pas la dernière révision, on peut annuler les intermédiaires (via git reset) jusqu'à ce qu'elle le devienne, puis ensuite, replacer les commits annulés avec :
git cherry-pick xxx
(où xxx est l'ID du commit)
Par ailleurs, certains logiciels clients Git permettent de rassembler plusieurs révisions sélectionnées depuis une liste, comme la fonction cherry-pick de SmartGit ou NetBeans qui permet de sélectionner des commits existant pour les intégrer à sa branche, ou git blame pour afficher les auteurs de chaque passage.
En console, annuler ou modifier un commit peut être réalisé de plusieurs manières :
git commit --amend --no-edit
git reset HEAD~1
git rebase -i
(puis squash)
En cas de réécriture d'historique, le hash du commit change, ce qui ne pose pas de problème en local mais complexifie considérablement les rebases des branches issues de celle réécrite, car Git voit des conflits entre le commit original et celui réécrit[2].
Pour modifier le résumé d'un ancien commit (xxx) : git rebase --interactive 'xxx^'
Il faut donc éviter de les multiplier : ne pas en enchainer plusieurs avec le même résultats, ou en créer des “fix” du précédent. Il faut les casser et les regrouper. Ainsi les rebase auront moins de conflit, les git blame seront parlant et les git revert de feature deviendront possibles. Dans cette optique, il faut d'ailleurs préférer les rebases aux merges pour éviter l'ajout d'un commit de merge inutile nuisant à la lisibilité et à la taille du dépôt.
Enfin, éviter d’embarquer dans un commit un fichier qui ne contient qu’une modification d’espace ou de retour chariot pour limiter les tailles d’historique et les conflits de merge.Recherche dans l'historique
[modifier | modifier le wikicode]Pour rechercher un mot dans tous les historiques de tous les fichiers (du répertoire et des sous-répertoires du script) :
git rev-list --all | (
while read revision; do
git grep -F 'mon_mot_clé' $revision
done
)
Par ailleurs, git bisect
permet de rechercher dans l'historique des révisions en définissant les mauvais et bon commits[3].
Continuer
[modifier | modifier le wikicode]Vous maîtrisez désormais le strict minimum pour travailler avec git. Vous pouvez ajouter, modifier et supprimer des fichier et enregistrer les changements dans votre dépôt local ainsi que consulter l'historique des modifications. Cela reste toutefois une vision simpliste de la gestion de projet et nous verrons dans la suite comment exploiter les branches locales et comment partager votre travail avec d'autres contributeurs en publiant vos modifications sur un dépôt distant et en récupérant les modifications des autres contributeurs.
Références
[modifier | modifier le wikicode]- ↑ http://git-scm.com/docs/git-add
- ↑ « Rewriting Git History », Git’s now confused
- ↑ https://git-scm.com/docs/git-bisect
- https://learngitbranching.js.org/ : explications schématisées
Branches
Précédemment, nous avons vu comment apporter des modifications à une branche telles que ajouter, modifier ou supprimer un fichier et commit
nos modifications. Cela fonctionne parfaitement et cela peut suffire pour travailler seul sur un petit projet. Toutefois, ce n'est pas la meilleure façon de procéder sous git qui propose des mécanismes plus élaborés pour développer sur un projet.
L'approche de git est de favoriser l'utilisation de branche pour toute modification du code de l'application.
Ainsi, il ne faut jamais travailler directement sur la branche *master* : cette branche doit rester stable et ne doit être utilisée que pour baser son travail dans d'autres branches.
Pour mieux comprendre, nous allons refaire, pas à pas, exactement les mêmes modifications que celles que nous avons faites précédemment mais, cette fois, nous allons utiliser une branche afin de nous familiariser avec ce concept.
Reprenons notre dépôt d'exemple :
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
cd examples
Créer une première branche
[modifier | modifier le wikicode]D'abord, demandons à git de nous indiquer où nous en sommes au niveau des branches :
git branch
* master
Git nous indique qu'il existe une seule branche appelée master
et que c'est sur cette branche que nous travaillons comme l'indique l'astérisque en face de master
.
Créons une nouvelle branche que nous allons appeler ma-branche
.
git branch ma-branche
Constatons les effets :
git branch ma-branche
ma-branche * master
Il y a maintenant deux branches : *master* et *ma-branche*. Actuellement, nous travaillons toujours sur *master* comme l'indique toujours l'astérisque.
git log --decorate --graph
On peut voir, sur la première ligne que *master* et *ma-branche* sont au même niveau, sur le même commit. Nous allons maintenant demander à git de nous basculer sur *ma-branche* afin de pouvoir travailler sur celle-ci et non sur *master*.
git checkout ma-branche
Switched to branch 'ma-branche'
On a basculé, et git branch
nous le confirme.
git branch
* ma-branche master
git checkout -b ma-branche
pour créer et sélectionner une nouvelle branche en même temps.git checkout -f branche2
. Cela évite de faire un git clean -f -d
(discard all) avant.
git checkout .
supprime le code non commité.
Faire les modifications
[modifier | modifier le wikicode]On peut désormais faire les modifications dans ma-branche que l'on peut développer, sans prendre le risque de modifier master.
Faisons les mêmes modifications que précédemment :
echo "Ceci est un test de git" > mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'un fichier"
echo "Une seconde ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une seconde ligne dans le fichier"
echo "Une troisième ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une troisième ligne dans le fichier"
Et ainsi de suite. Vous pouvez commiter et faire autant de commits que vous voulez dans ma-branche.
L'idée est que pour chaque évolution du logiciel développé, il faut créer une branche. Ainsi, on peut garder la branche aussi longtemps que nécessaire et continuer de travailler dessus tant qu'on a pas fini la fonctionnalité.
Regardons le log
que cela produit :
git log --decorate --graph
* commit 635ace69f901dfb1aaff187e6abc54b0c95fe51e (HEAD, ma-branche) | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 23:33:15 2014 +0200 | | ajout d'une troisième ligne dans le fichier | * commit dbc6c57019afe80dbb2f3d889eb63cb024656faa | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 23:33:14 2014 +0200 | | ajout d'une seconde ligne dans le fichier | * commit e2cbadc10289e74a131a728e06ac2421e79b5b9f | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 23:33:14 2014 +0200 | | ajout d'un fichier | * commit a59a042e1a7f1474a11c0bd2585ab2eb71b85c47 (origin/master, origin/HEAD, master) |\ Merge: 5c511f2 12c8449 | | Author: Darkdadaah <darkdadaah@yahoo.fr> | | Date: Sat May 25 08:49:21 2013 +0000 | | | | Merge "TEST 1" | |
Examinons ce graphique : master est en retard tandis que ma-branche est en avance de trois commits.
Fusionner la branche dans master (merge)
[modifier | modifier le wikicode]Supposons que nous sommes satisfaits du travail réalisé dans notre branche. Nous avons fait plusieurs commits, nous avons vérifié que nous n'avons pas créé de bogue, etc. Supposons que notre branche est prête et qu'on peut intégrer les modifications dans master.
D'abord, se placer sur master :
git checkout master
Switched to branch 'master'
Puis demander à git de fusionner la branche ma-branche, sans fast forward[1] pour éviter de perdre la topologie de la branche :
git merge ma-branche --no-ff -m "intégration de ma nouvelle fonctionnalité dans master"
Git va faire un commit pour intégrer les changements. Comme précédemment, nous avons choisi d'utiliser -m
pour préciser le message de commit mais on aurait pu ne rien mettre et git nous aurait ouvert l'éditeur de texte.
Merge made by the 'recursive' strategy. mon_nouveau_fichier.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 mon_nouveau_fichier.txt
Examinons
git log --decorate --graph
* commit abd3ef0a5978b90db042bf076e82d64c3576194b (HEAD, master) |\ Merge: a59a042 635ace6 | | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | | Date: Tue Jul 22 23:43:51 2014 +0200 | | | | intégration de ma nouvelle fonctionnalité dans master | | | * commit 635ace69f901dfb1aaff187e6abc54b0c95fe51e (ma-branche) | | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | | Date: Tue Jul 22 23:33:15 2014 +0200 | | | | ajout d'une troisième ligne dans le fichier | | | * commit dbc6c57019afe80dbb2f3d889eb63cb024656faa | | Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | | Date: Tue Jul 22 23:33:14 2014 +0200 | | | | ajout d'une seconde ligne dans le fichier | | | * commit e2cbadc10289e74a131a728e06ac2421e79b5b9f |/ Author: Michel Boudran <michel.boudran@fr.wikibooks.org> | Date: Tue Jul 22 23:33:14 2014 +0200 | | ajout d'un fichier | * commit a59a042e1a7f1474a11c0bd2585ab2eb71b85c47 (origin/master, origin/HEAD)
On retrouve bien quatre commits nous appartenant (symbolisés par une * dans le graphe). On retrouve les trois premières modifications et un quatrième commit pour le merge
. On voit que les branches ont convergé sur le graphique et que master est de nouveau sur la première ligne tout en haut du graphe. Nos changements ont bien été intégré à master.
Effacer une branche
[modifier | modifier le wikicode]Locale
[modifier | modifier le wikicode]Nos changements sont intégrés à master, la branche est désormais inutile. Supprimons-la :
git branch -d ma-branche
Deleted branch ma-branche (was 635ace6).
La suppression de la branche peut échouer si la branche à supprimer n'a pas été fusionnée dans master :
git branch -d ma-branche
error: The branch 'ma-branche' is not a strict subset of your current HEAD. If you are sure you want to delete it, run 'git branch -D dev'.
Git se prémunit donc d'effacer des changements potentiellement non vérifiés. Comme git l'indique, on peut forcer la suppression malgré tout :
git branch -D ma-branche
NB : une branche ne peut pas être supprimée si on n'a pas fait le dernier commit.
Distante
[modifier | modifier le wikicode]git push <remote_name> --delete <branch_name>
Supprimer les veilles branches
[modifier | modifier le wikicode]Lorsque l'on tape "git branch" après un certain temps, la branche active apparait au milieu d'une multitude d'anciennes branches généralement fusionnées, et donc inutile de conserver en local. Pour les nettoyer on utilise donc :
git remote prune origin
Mais parfois il reste encore un paquet de branches locales qui ont été mergées sur le serveur. Pour éviter d'avoir à les supprimer une par une :
git branch -D `git branch --merged | grep -v \* | xargs`
Sinon, nommer la branche dans laquelle elles furent fusionnées. Par exemple, pour supprimer les branches mergées dans "master" :
git branch -D `git branch --merged master | grep -v \* | xargs`
Renommer une branche
[modifier | modifier le wikicode]Il faut renommer la locale, supprimer la distante, puis pusher la locale :
git branch -m vieille_branche nouvelle_branche
git push origin :vieille_branche
git push --set-upstream origin nouvelle_branche
L'option --set-upstream
(alias -u
) s'utilise uniquement à la création de la branche sur le serveur distant. Elle doit ensuite être mise à jour avec push
tout court.
Continuer
[modifier | modifier le wikicode]Vous pouvez à tout moment créer des nouvelles branches depuis master et ce, à chaque nouvelle fonctionnalité ou nouvelle modification qu'il faudrait apporter au projet. Git vous permet de gérer plusieurs branches en parallèle et ainsi de cloisonner vos travaux et d'éviter de mélanger des modifications du code source qui n'ont rien à voir entre elles.
En gardant une branche master saine, vous vous laissez la possibilité de créer de nouvelles branches simplement et vous conservez ainsi une version du logiciel prête à être livrée à tout instant (puisqu'on ne merge
dedans que lorsque le développement est bien terminé.
git log
vous permet de retrouver dans l'historique les branches qui ont été créées, et les différents commits réalisés pour une même fonctionnalité sont bien regroupés entre eux.
Références
[modifier | modifier le wikicode]
Synchroniser le dépôt local avec le dépôt distant
Dans le chapitre précédent, nous avons vu comment vous pouviez travailler seul dans votre dépôt local. Nous allons maintenant nous pencher sur l'aspect distribué de git et voir comment travailler de façon collaborative en communiquant avec d'autres dépôts. Nous allons voir comment publier vos modifications et recevoir les modifications des autres développeurs.
Simulons un environnement de travail distribué
[modifier | modifier le wikicode]Nous allons faire travailler ensemble deux personnages, dont la réputation n'est plus à faire, Alice et Bob. Nous allons supposer que Alice et Bob vont chacun créer leur dépôt local sur leur machine avec git clone. Bien évidemment, ils vont utiliser clone en indiquant l'adresse du dépôt principal du projet : http://
, https://
, git://
ou file:////
.
Pour créer un dépôt HTTP(s), il faut qu'il soit lisible par un serveur web (ex : Apache).
Créons un faux dépôt distant pour nos tests
[modifier | modifier le wikicode]Il serait prématuré d'expliquer ici comment créer un dépôt sur le réseau. Aussi, pour travailler, nous allons créer un faux dépôt distant en local.
Placez-vous dans un dossier qui ne risque rien (par exemple /tmp
), nous allons créer le faux dépôt distant.
mkdir tests-avec-git
cd tests-avec-git
git init faux-depot-distant --bare
Initialized empty Git repository in /tmp/tests-avec-git/faux-depot-distant/
Les fichiers d'un dépôt --bare
sont cryptés dans le sous-répertoire objects
, ils ne sont donc pas accessibles par d'autres programmes que Git.
Simulons deux utilisateurs utilisant le dépôt distant
[modifier | modifier le wikicode]Le faux dépôt distant est créé. Maintenant, Alice et Bob vont créer leur copie locale avec clone.
git clone faux-depot-distant depot-local-alice
cd depot-local-alice
git config user.email "alice@fr.wikibooks.org"
git config user.name "Alice"
# Idem pour Bob
cd ..
git clone faux-depot-distant depot-local-bob
cd depot-local-bob
git config user.email "bob@fr.wikibooks.org"
git config user.name "Bob"
Alice commence à travailler
[modifier | modifier le wikicode]En tant qu'Alice, créons quelques modifications.
cd depot-local-alice
echo "Ceci est un test de git" > mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'un fichier"
echo "Une seconde ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une seconde ligne dans le fichier"
echo "Une troisième ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une troisième ligne dans le fichier"
Alice a maintenant quelques modifications dans son dépôt local, nous allons voir comment elle peut échanger avec Bob.
Commencer à travailler avec un dépôt distant
[modifier | modifier le wikicode]Dès que vous voulez faire une opération qui concerne le dépôt distant (publication ou récupération d'informations), commencez toujours par
git fetch
Cela met à jour les informations sur les dépôts distants auxquels est rattaché votre dépôt local, si vous oubliez de le faire, vous risquez d'être faussé par le fait que l'historique des modifications que vous voyez (par exemple) n'est pas complet.
Ainsi, dès que vous voulez faire une opération qui implique le dépôt distant, souvenez-vous de toujours faire un git fetch.
Publier les modifications locales sur le dépôt distant
[modifier | modifier le wikicode]Alice a fait plusieurs modifications sur master, elle voudrait les partager avec Bob, elle doit donc publier ses derniers commits sur le dépôt distant.
git push origin master
Counting objects: 9, done. Delta compression using up to 4 threads. Compressing objects: 100% (7/7), done. Writing objects: 100% (9/9), 787 bytes | 0 bytes/s, done. Total 9 (delta 1), reused 0 (delta 0) To /tmp/tests-avec-git/faux-depot-distant * [new branch] master -> master
Git nous indique que la branche master a été créée sur le dépôt distant.
Récupérer les modifications d'un dépôt distant
[modifier | modifier le wikicode]Voyons comment Bob peut récupérer le travail d'Alice.
cd depot-local-bob git fetch
remote: Counting objects: 9, done. remote: Compressing objects: 100% (7/7), done. remote: Total 9 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (9/9), done. Depuis /tmp/tests-avec-git/faux-depot-distant * [nouvelle branche] master -> origin/master
Git nous indique qu'une nouvelle branche a été créée sur le dépôt distant. On va essayer de la récupérer.
git checkout master git log
git log commit 99d23406a342a94dd8c7be9c21a47d6d11b8d7f0 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:04 2014 +0100 ajout d'une troisième ligne dans le fichier commit 659937374dd1612ea8f33c07173f45aa42cabce1 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'une seconde ligne dans le fichier commit a3b17da118bf2cfda9e6bcb6f70d305566827373 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'un fichier
On a bien récupéré les modifications faites par Alice. Si vous ouvrez le fichier mon_nouveau_fichier.txt, vous retrouverez toutes les modifications d'Alice.
cat mon_nouveau_fichier.txt
Ceci est un test de git Une seconde ligne Une troisième ligne
À notre tour, faisons une modification :
echo "Une quatrième ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une quatrième ligne dans le fichier"
git log
commit 6b99e801c2b37535a84fa6f73510b720f8aeeb31 Author: Bob <bob@fr.wikibooks.org> Date: Sat Nov 15 11:37:13 2014 +0100 ajout d'une quatrième ligne dans le fichier commit 99d23406a342a94dd8c7be9c21a47d6d11b8d7f0 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:04 2014 +0100 ajout d'une troisième ligne dans le fichier commit 659937374dd1612ea8f33c07173f45aa42cabce1 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'une seconde ligne dans le fichier commit a3b17da118bf2cfda9e6bcb6f70d305566827373 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'un fichier
Le résultat de ce git log ne devrait pas vous surprendre. Néanmoins, cette sortie ne montre pas l'état du dépôt distant. Pour cela, nous allons utiliser l'option --decorate.
git log --decorate
commit 6b99e801c2b37535a84fa6f73510b720f8aeeb31 (HEAD, master) Author: Bob <bob@fr.wikibooks.org> Date: Sat Nov 15 11:37:13 2014 +0100 ajout d'une quatrième ligne dans le fichier commit 99d23406a342a94dd8c7be9c21a47d6d11b8d7f0 (origin/master) Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:04 2014 +0100 ajout d'une troisième ligne dans le fichier commit 659937374dd1612ea8f33c07173f45aa42cabce1 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'une seconde ligne dans le fichier commit a3b17da118bf2cfda9e6bcb6f70d305566827373 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'un fichier
Là, on voit bien que notre branche master locale (master) est en avance de un commit sur la branche master distante (origin/master). HEAD indique simplement le commit sur lequel nous nous trouvons. Cela est confirmé par git status :
git status
Sur la branche master Votre branche est en avance sur 'origin/master' de 1 commit. (utilisez "git push" pour publier vos commits locaux) rien à valider, la copie de travail est propre
Publions nos modifications comme git nous le propose :
git push
Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 341 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To /tmp/tests-avec-git/faux-depot-distant 99d2340..6b99e80 master -> master
On retourne chez Alice :
cd depot-local-alice
git status
Sur la branche master Votre branche est à jour avec 'origin/master'. rien à valider, la copie de travail est propre
La copie d'Alice semble à jour. Mais où est passé la modification de Bob ? Nous avons oublié le git fetch !
git fetch
git status
Sur la branche master Votre branche est en retard sur 'origin/master' de 1 commit, et peut être mise à jour en avance rapide. (utilisez "git pull" pour mettre à jour votre branche locale) rien à valider, la copie de travail est propre
Cette fois-ci, git nous indique que nous sommes en retard de 1 commit, en effet nous n'avons pas récupéré les modifications de Bob. Voyons ce que donne git log. Cette fois-ci, nous allons utiliser l'option --all pour indiquer à git que nous voulons voir toutes les branches, c'est à dire que nous voulons voir origin/master et pas seulement master.
git log --decorate --all
commit 6b99e801c2b37535a84fa6f73510b720f8aeeb31 (origin/master) Author: Bob <bob@fr.wikibooks.org> Date: Sat Nov 15 11:37:13 2014 +0100 ajout d'une quatrième ligne dans le fichier commit 99d23406a342a94dd8c7be9c21a47d6d11b8d7f0 (HEAD, master) Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:04 2014 +0100 ajout d'une troisième ligne dans le fichier commit 659937374dd1612ea8f33c07173f45aa42cabce1 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'une seconde ligne dans le fichier commit a3b17da118bf2cfda9e6bcb6f70d305566827373 Author: Alice <alice@fr.wikibooks.org> Date: Sat Nov 15 11:27:02 2014 +0100 ajout d'un fichier
On voit bien notre retard sur le commit de Bob puisque origin/master est plus haut que master. Demandons à git de récupérer les modifications distantes et de les fusionner avec notre master local.
git pull
Mise à jour 99d2340..6b99e80 Fast-forward mon_nouveau_fichier.txt | 1 + 1 file changed, 1 insertion(+)
Et ainsi de suite. Chacun peut localement faire plusieurs commits et faire régulièrement git push
(« pousser » en anglais) pour publier ses propres modifications et des pull (« tirer » en anglais) pour récupérer les modifications des autres.
git pull origin nom_de_branche
ne récupère que les informations de celle-ci.Continuer
[modifier | modifier le wikicode]Vous maîtrisez maintenant l'essentiel de git pour pouvoir travailler collaborativement sur un projet.
Évidemment, dans notre exemple, nous avons utilisé un faux dépôt distant. Dans la réalité, il faudra créer un dépôt central (régulièrement sauvegardé pour ne pas perdre le projet !) sur une machine réseau pour que tout le monde puisse faire le clone.
Étiquetage (tags)
Principe
[modifier | modifier le wikicode]Git permet d'ajouter des étiquettes (tags en anglais), parfois appelées "balises" (par exemple sur Bitbucket), pour spécifier des versions dans les historiques[1] :
git tag -a tag1
ou :
git tag -f tag1 HEAD
Pour lister les tags :
git tag
Se positionner sur un tag :
git checkout tags/0.3.4
Envoyer les tags sur le serveur distant :
git push --tags
Supprimer un tag local :
git tag -d v1.4.9
Supprimer un tag sur le serveur :
git push --delete origin v1.4.9
Il est déconseillé de supprimer les tags pour tracer l'historique des codes déployés.
Pour recréer un tag :
git push --delete origin v0.0.1 ; git tag -a v0.0.1 -f && git push --tags
Ou plus rapidement en gardant son message :
git tag -d 3.0.2 ; git tag -a 3.0.2 -f -m "Résumé" && git push --tags -f
Étiquettes vs branches
[modifier | modifier le wikicode]Les étiquettes comme les branches pointent vers une soumission, la différence est que la branche pointe toujours en haut de la ligne de développement et est remplacée par les soumissions postérieures, alors que l'étiquette demeure inchangée.
En pratique, les tags sont donc utilisés pour désigner les versions du programme, et sont donc nommés avec des numéros, si possible selon la SemVer (ex : v1.0.2)[2].
git push origin :refs/tags/v1.1.0
git tag -fa v1.1.0
git push origin master --tags
Références
[modifier | modifier le wikicode]
Remise (stash)
Remiser des changements
[modifier | modifier le wikicode]Cette fonctionnalité permet de remiser des modifications locales quand vous souhaitez changer de branches et que vous ne souhaitez pas les indexer ("git add") ou les ajouter à votre dépôt local ("git commit").
Remiser des modifications (fichiers suivis ou indexés) :
git stash
La remise se comporte comme une pile ; les dernières modifications remisées sont placées au sommet de la pile.
Vous pouvez visualiser le contenu de votre remise avec la commande :
git stash list
Remiser des modifications et des créations (fichiers non suivis ou non indexés) :
git stash save -u
Annuler un merge suite à un stash conflictuel :
git reset --merge
Appliquer une remise
[modifier | modifier le wikicode]Pour appliquer les dernières modifications remisées en les supprimant de la remise :
git stash pop
Note : cette commande est équivalente à "git stash pop stash@{0}".
Pour appliquer les dernières modifications remisées en les laissant dans la remise :
git stash apply
Note : cette commande est équivalente à "git stash apply stash@{0}".
Il est possible d'appliquer ces commandes à n'importe quelles modifications remisées (par exemple "git stash apply stash@{2}").
Inspecter le contenu d'une remise
[modifier | modifier le wikicode]Pour inspecter les dernières modifications remisées :
git stash show
Pour comparer le contenu de la remise avec le commit tel qu'il était lorsque le remisage a été effectué :
git stash show -p
Il est possible d'appliquer ces commandes à n'importe quelles modifications remisées (par exemple "git stash show -p stash@{1}").
Supprimer toutes les remises
[modifier | modifier le wikicode]git stash clear
Recombinaison (rebase)
Recombinaison (rebase)
[modifier | modifier le wikicode]Le rebase permet de mettre à jour sa branche par-dessus une autre. Généralement on rebase une branche par rapport à la branche principale (main) :
git rebase main
En cas de conflit, c'est-à-dire si une même ligne a été modifiée à la fois sur "main" et sur la branche à rebaser, le rebase s'arrête et on doit modifier le fichier pour déterminer le résultat final du commit déplacé. Puis on reprend le rebase avec :
git add -A git rebase --continue
Si on ne veut pas passer du temps à régler manuellement chaque conflit, on peut le faire automatiquement :
- En conservant les modifications de la branche de départ :
git rebase origin/master -s recursive -X theirs
- En conservant celles de la branche rebasée :
git rebase origin/master -s recursive -X ours
rebase -i
[modifier | modifier le wikicode]Pour changer les messages des soumissions, leur ordre ou leur nombre, on peut utiliser le mode interactif (-i). Exemples :
- sur la branche "main" :
git rebase -i main
- sur les trois derniers commits :
git rebase -i HEAD~3
On peut effacer et fusionner des soumissions en choisissant l'option "s" (squash) ou changer leur ordre.
Pour annuler le rebase en cours :
git rebase --abort
Sous-modules et Super-projets
Le super-projet est un concept apparu avec Git depuis v1.5.3, ayant pour but de mieux gérer de nombreux dépôts, en distinguant ceux qui sont hors du super-projet, de ceux à l'intérieur que l'on appelle les sous-modules.
Super-projets
[modifier | modifier le wikicode]Un super-projet est un dépôt Git, que l'on crée via git init
dans le répertoire, puis git submodule add
suivi des archives à inclure :
$ git submodule add ./examples
Adding existing repo at 'examples' to the index
warning: LF will be replaced by CRLF in .gitmodules.
The file will have its original line endings in your working directory.
$
La structure résultante est de la forme suivante :
|- super-projet |- sous-module (archive Git) [a] |- sous-module [b] |- sous-module [c] |- sous-module [d]
Si quelqu'un récupère le super-projet, il trouvera une série de répertoire vide pour chaque sous-module. Pour les utiliser, il faut lancer git submodule init
pour chacun.
Sous-modules
[modifier | modifier le wikicode]Une archive Git est considérée comme sous-module après avoir exécuté git submodule add
dans un autre dépôt.
Workflow
[modifier | modifier le wikicode]Le flux de travail des super-projets et des sous-modules dit généralement adhérer à l'ordre :
- Changement du sous-module.
git commit
du sous-modulegit commit
du super-projetgit submodule update
pour envoyer les changements aux différents dépôts antérieurs au super-projet.
Structure interne
Structure de Git brute
[modifier | modifier le wikicode]Le schéma suivant représente un dépôt Git v1.5.2.5[1].
. └── .git/ ├── HEAD ├── branches/ ├── config ├── description ├── hooks/ │ ├── applypatch-ms │ ├── commit-msg │ ├── post-commit │ ├── post-receive │ ├── post-update │ ├── pre-applypatc │ ├── pre-commit │ ├── pre-push │ ├── pre-rebase │ └── update ├── info/ │ └── exclude ├── objects/ │ ├── info/ │ └── pack/ └── refs/ ├── heads/ └── tags/
Fichiers
[modifier | modifier le wikicode]HEAD
[modifier | modifier le wikicode]HEAD indique le code actuellement vérifié. Généralement le point de la branche sur lequel on travaille.
Il est possible d'ajouter un état "HEAD détaché", en dehors de la branche locale. Dans ce cas la tête pointe sur une soumission et non sur une branche.
config
[modifier | modifier le wikicode]Le fichier de configuration pour ce dépôt Git. Il peut contenir les paramètres permettant de gérer et stocker les données dans le dépôt local, les distants connus, et les informations sur les utilisateurs (local et autres).
description
[modifier | modifier le wikicode]Utilisé par les outils du navigateur de dépôt, contient une description du projet, généralement inchangée dans les dépôts non partagés.
Dossiers
[modifier | modifier le wikicode]Branches
[modifier | modifier le wikicode]hooks
[modifier | modifier le wikicode]Contient les scripts à lancer quand des évènements particuliers surviennent dans le dépôt Git.
Ces points d'entrée sont utilisés par exemple pour lancer des tests avant chaque soumission, filtrer le contenu uploadé, et implémenter ce genre de personnalisations.
Exemple
[modifier | modifier le wikicode]cp .git/hooks/pre-push.sample .git/hooks/pre-push vim .git/hooks/pre-push
info
[modifier | modifier le wikicode]objects
[modifier | modifier le wikicode]Stocke les listes de répertoires, fichiers et soumission.
Il y a les objets non compressés des nombreux répertoires, et les "packs" d'objets compressés. Les premiers sont régulièrement collectés via git gc
.
refs
[modifier | modifier le wikicode]Contient les informations où les branches pointent. Inclut normalement des répertoires "heads" pour les branches locales, et "remotes" pour les copies des branches distantes. Toutes les branches ne figurent pas dans ces répertoires. Celles qui n'ont pas changé récemment sont listées dans le fichier .git/packed-refs.
Fichiers Git hors dossier .git
[modifier | modifier le wikicode].gitkeep
[modifier | modifier le wikicode]Placé dans un dossier, il garantit qu'il sera commité même vide.
.gitignore
[modifier | modifier le wikicode]Liste les fichiers et dossiers à exclure du versioning. Ex :
/var/ /vendor/ /.env.*.local
.gitattributes
[modifier | modifier le wikicode]Contient des attributs[3]. Par exemple pour ignorer .gitattributes et .gitignore des exports effectués par "git archive" :
.gitattributes export-ignore .gitignore export-ignore
Références
[modifier | modifier le wikicode]- ↑ Généré avec la commande tree v1.5.1.1 :
tree -AnaF
. - ↑ https://www.viget.com/articles/two-ways-to-share-git-hooks-with-your-team/
- ↑ https://git-scm.com/docs/gitattributes
pull-request
Principe
[modifier | modifier le wikicode]Une fois un dépôt distant cloné en local, il est facile de mettre régulièrement à jour sa version, à l'aide de la commande git pull
depuis le répertoire du dépôt (via crontab par exemple).
Par contre pour envoyer ses versions développées localement sur le dépôt distant, cela nécessite une pull request (alias PR, ou merge request, MR, voire demande de tirage).
git request-pull
Intérêt
[modifier | modifier le wikicode]- Déclencher une notification que le code est prêt à être fusionné, ce qui n'est pas le cas à chaque fois qu'on modifie une branche. Celle-ci a lieu généralement par email mais selon le serveur on peut configurer un hook vers du tchat ou autre.
- S’assigner la traitement de la PR.
- Joindre du texte non versionné dans Git, dans la description de la PR (ex : les cas de test). Et lister les retours de relecture / test de la branche. Ces retours peuvent même être configurés comme bloquant automatiquement le merge tant que pas résolus.
- Bloquer le merge si le résultat des pipelines CI sont en erreur.
- Voir les conflits dans la liste des PR à traiter.
- Supprimer les branches automatiquement après merge.
Mise à jour
[modifier | modifier le wikicode]Si la branche a été mise à jour depuis un autre client, git gère la fusion automatiquement si les fichiers modifiés sont différents. Par contre s'il y en a en commun, il faut procéder manuellement avec un rebase interactif :
git rebase -i origin/MaBranche1
Pour éviter cela, il faut bien vérifier que la branche sur laquelle on commence à travailler est bien la dernière version, avec :
git fetch origin/MaBranche1
- Ne pas lancer de
pull
après unrebase
sous peine d'inclure dans sa branche locale, les commits effectués entre-temps sur la branche principale. - Ne pas lancer un
push
après unreset
total de la branche, car une PR sans commit sera automatiquement fermée.
Références
[modifier | modifier le wikicode]
Recettes
Supprimer un fichier du dépôt tout garder le fichier
[modifier | modifier le wikicode]git rm fichier.txt
supprime le fichier du dépôt mais supprime aussi le fichier local.
Pour ne l'enlever que du dépôt, utiliser git rm --cached fichier.txt
.
Ajouter "-r" pour les dossiers.
Annuler une soumission
[modifier | modifier le wikicode]Quand on ne peut pas réécrire l'historique (par exemple en production) mais qu'il faut annuler un commit, on utilise git revert
avec HEAD pour désigner la dernière soumission effectuée :
$ git revert HEAD
Finished one revert.
[master 47e3b6c] Revert "Soumission 2"
1 files changed, 0 insertions(+), 1 deletions(-)
$ ls -a
. .. fichier.txt .git
Pour signifier d'autres soumissions que la dernière :
git revert HEAD^
: l'avant dernière.git revert HEAD~5
: la cinquième moins récente.git revert e6337879
: la soumission n°e6337879.
Ensuite, il est recommandé de vérifier que le rollback a bien fonctionné en s'assurant de l'absence de différence entre le code actuel et celui de n-1 (où n est le nombre de commits annulés)[1]
git revert --no-commit HEAD~2..HEAD
git diff HEAD~3 HEAD
Annuler un merge
[modifier | modifier le wikicode]On ne peut pas annuler un merge comme un commit, il faut indiquer le nombre reverté (où réverter un seul merge de plusieurs commits reverte tous les commits) :
git revert -m 1
Nettoyer les changements non soumis
[modifier | modifier le wikicode]Pour annuler les modifications de fichiers non soumises (discard) :
git clean -f
Pour annuler les créations de fichiers non soumises :
git stash save -u git stash drop "stash@{0}"
Annuler les changements soumis
[modifier | modifier le wikicode]reset
[modifier | modifier le wikicode]Par ailleurs, il existe plusieurs niveaux de reset[2] :
- soft : ne touche pas à l'index ni au répertoire de travail. Les fichiers en reset retournent juste de la liste des commités à celle à commiter.
- hard : efface l'index et le répertoire de travail. Cette option équivaut à un reset + clean.
- mixed : celui par défaut, mélange des deux précédents. Il laisse les fichiers du répertoire de travail, mais annule l'index.
- merge
- keep
Pour effacer les changements en cours, en rétablissant les états de la dernière soumission :
$ git reset --hard HEAD
ou
$ git reset --hard e6337879
Pour ne toucher qu'un seul fichier :
$ git checkout fichier.txt
- Pour effacer les deux derniers commits sans toucher aux fichiers :
git reset 'HEAD~2'
. - Pour effacer les deux derniers commits et leurs modifications dans les fichiers :
git reset HEAD~2 --hard
. - Pour revenir deux opérations en arrière sur la branche :
git reset HEAD@{2}
(utilise la liste des opérations visible dansgit reflog
). Cela peut donc permettre d'annuler un reset malencontreux.
restore
[modifier | modifier le wikicode]git restore
revient à la version du fichier spécifié en paramètre[3].
Par exemple, pour restaurer tous les fichiers du dossier courant :
git restore .
Pour annuler des "git add" (donc retirer un fichier de la zone de transit) :
git restore --staged mon_fichier.txt
Récupérer une version de fichier
[modifier | modifier le wikicode]Il faut d'abord récupérer l'identifiant de la version avec git log
:
$ git log
commit 47e3b6cb6427f8ce0818f5d3a4b2e762b72dbd89
Author: NomUtilisateur <NomEmail@exemple.com>
Date: Sat Mar 6 22:24:00 2010 -0400
Revert "Soumission 2"
This reverts commit e6337879cbb42a2ddfc1a1602ee785b4bfbde518.
commit e6337879cbb42a2ddfc1a1602ee785b4bfbde518
Author: NomUtilisateur <NomEmail@exemple.com>
Date: Sat Mar 6 22:17:20 2010 -0400
My second commit
commit be8bf6da4db2ea32c10c74c7d6f366be114d18f0
Author: NomUtilisateur <NomEmail@exemple.com>
Date: Sat Mar 6 22:11:57 2010 -0400
My first commit
Ensuite pour lire la version, utiliser git show
:
$ git show e6337879cbb42a2ddfc1a1602ee785b4bfbde518:fichier.txt
Test Git Wikilivres.
test de suppression Git pour Wikilivres
Créer et appliquer un patch
[modifier | modifier le wikicode]Créer un patch[4] génère un texte de toute la série des changements entre les branches origines et master.
$ git format-patch origin/master
Pour appliquer un patch :
$ git apply --stat P1.txt # affiche les stats des changements $ git apply --check P1.txt # vérifie les problèmes $ git am < P1.txt # applique le patch dans l'ordre
Le patch est aussi le mode de transfert entre dépôts.
Références
[modifier | modifier le wikicode]
Exclure des fichiers du dépôt
Principe
[modifier | modifier le wikicode]Souvent il y a des fichiers dans l'espace de travail qui ne sont pas souhaitables dans le dépôt :
- Les fichiers générés temporairement. Par exemple,
emacs
crée automatiquement une copie des fichiers édités avec, avec un suffixe tilde, commefichier1~
. Il faut donc éviter manuellement de les soumettre. - Les fichiers de secours (backup) comme, par exemple, les fichiers .bak générés par les outils de comparaison de fichiers après des opérations de fusion.
- Les fichiers générés lors de la compilation,
- ...
Certains fichiers (notamment ceux générés lors de la compilation) sont en général situés dans un répertoire particulier, qu'il est possible d'exclure des dépôts Git.
.gitignore
[modifier | modifier le wikicode]Pour dire à Git d'ignorer certains fichiers, il est possible de créer un fichier .gitignore
. Chaque ligne y représente une spécification (avec wildcards) des fichiers ou répertoires à ignorer. Des commentaires peuvent être ajoutés dedans sur les lignes débutant par un blanc ou un dièse :
# Ignorer les backups Emacs : *~ # Ignorer le répertoire ''cache'' : app/cache
Ce fichier sera ensuite automatiquement proposé pendant les commits, de sorte que tous les développeurs du dépôt auront la même liste de fichiers à ignorer.
De plus, certains caractères sont interprétés, comme le "!" en début de ligne qui signifie "sauf" (ex : exclure un dossier sauf un de ses fichiers)[1].
Si un fichier a déjà été commité, l'ajouter dans .gitignore ne changera rien : il faut d'abord le supprimer de la branche.
exclude
[modifier | modifier le wikicode]Pour n’ignorer des fichiers que sur son propre poste, il faut les placer dans .git/info/exclude
. Ainsi, ils ne seront jamais proposés pendant les commits.
Recherche
[modifier | modifier le wikicode]Pour déterminer les fichiers ignorés d'un dossier ou pourquoi un fichier est ignoré, utiliser "check-ignore". Exemple :
git check-ignore core/scripts/imagecopy.py -v
Références
[modifier | modifier le wikicode]
Écrire des messages de commit
Rédaction
[modifier | modifier le wikicode]Les bonnes pratiques sont[1][2] :
- 50 caractères maximum pour le titre, résumant les changements.
- Selon le contexte, la première ligne est traitée comme le sujet d'un email et le reste séparé par une ligne blanche, comme le corps du message.
- Utiliser le présent des verbes.
- Les listes à puces sont autorisées, typiquement avec un moins ou une astérisque.
- Le corps du message doit comprendre des lignes de 72 caractères maximum pour plusieurs raisons :
git format-patch --stdout
convertit une série de soumission en une série d'emails.- Le log Git ne revient pas automatiquement à la ligne, sans retour chariot il est donc étalé sur une seule ligne donc difficile à lire. Le nombre 72 est le résultat du calcul des 80 du terminal (selon la nétiquette des mails), moins les 4 de l'indentation et les 4 de sa symétrie à droite.
Les utilisateurs de Vim peuvent rencontrer ce prérequis lors de l'installation de vim-git, ou bien en le définissant dans la configuration des messages de soumission Git :
:set textwidth=72
Ceux de TextMate peuvent ajuster l'option colonne "Wrap" du menu "view", puis utiliser ^Q pour revenir à la ligne des paragraphes (s'assurer qu'il y a une ligne blanche après pour éviter le mélange avec les commentaires). Voici une commande shell pour ajouter 72 au menu afin de ne pas avoir à le faire glisser à chaque fois :
$ defaults write com.macromates.textmate OakWrapColumns '( 40, 72, 78 )'
Consultation
[modifier | modifier le wikicode]Ces résumés peuvent ensuite être lus via :
git log --pretty=oneline
affiche une courte liste des historiques avec identifiants et résumés.git rebase --interactive
fournit les résumés de ses propres soumissions.- Si l'option de configuration
merge.summary
est définie, les sommaires de toutes les soumissions seront fusionnés. git shortlog
n'affiche que les résumés des précédentes soumissions.git format-patch
,git send-email
.git reflog
, un historique local est accessible pour aider à retrouver d'éventuels erreurs.git blame
- Des interfaces graphiques :
La distinction sujet/corps de texte de Git permet donc un confort de recherche d'historique par rapport à d'autres logiciels similaires comme Subversion.
Références
[modifier | modifier le wikicode]- ↑ http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
- ↑ https://www.midori-global.com/blog/2018/04/02/git-50-72-rule
Intégration dans les IDEs
Git est intégré avec la plupart des IDEs, soit nativement, soit par installation d'extensions.
Eclipse
[modifier | modifier le wikicode]Eclipse intègre Git avec l'extension EGit (https://www.eclipse.org/egit/). Cette extension fournit une vue du dépôt Git. La configuration de Git est accessible dans la fenêtre des préférences sous le nœud "Team".
Parmi les opérations possibles :
- Cloner un dépôt Git,
- Créer un dépôt local,
- Commiter les changements,
- ...
Visual Studio Code
[modifier | modifier le wikicode]Visual Studio Code a une vue permettant de voir les fichiers modifiés, supprimés et ajoutés, de commiter les changements, et de synchroniser le dépôt local avec le dépôt distant (pull et push), l'extension « Git Graph » permet de visualiser le log des changements et les branches.
PhpStorm
[modifier | modifier le wikicode]PhpStorm possède un plugin "Git" permettant de voir l'historique des modifications des fichiers en couleur. On y accède par un onglet en bas, côté du terminal, ou par un clic droit sur un dossier ou fichier dans le menu de navigation à gauche, ou encore avec un clic droit dans la marge d'un fichier versionné ouvert puis afficher des annotations. Ce dernier chemin lance un "git blame" pour retrouver l'auteur de chaque ligne du fichier, et on peut ensuite réitérer l'opération en affichant les annotations précédentes pour remonter tout l'historique.
De plus, quand on regarde le différentiel des fichiers modifiés depuis le dernier commit (onglet "Version Control" en bas, "resolve", puis "merge..."), en cas de conflit il propose un outil de résolution à trois colonnes très ergonomique.
Enfin, il est recommandé d'ajouter le dossier .idea/ créé par PhpStorm dans le fichier .gitignore car il n'est pas censé être le même sur toutes les machines.
Améliorer sa productivité en configurant Git
Dans ce chapitre, nous allons voir comment vous pouvez adapter git à vos propres besoins.
Apprendre à configurer git
[modifier | modifier le wikicode]Vous pouvez intervenir à trois niveaux :
- Au niveau system
- dans ce cas, la configuration s'appliquera à tous les utilisateurs de votre système.
- Au niveau global
- dans ce cas, la configuration sera appliquée à vous seul utilisateur et pour tous les dépôts. C'est l'option la plus courante.
- Au niveau local
- dans ce cas, la configuration sera appliquée uniquement à ce dépôt.
Vous avez deux possibilités :
- Travailler avec la commande
git config
- Vous devrez donc utiliser respectivement
--system
,--global
ou ne pas mettre d'argument (git appliquera la commande au dépôt). - Modifier le fichier de configuration de git (avec un éditeur de texte)
- Vous devrez donc modifier respectivement les fichiers
/etc/gitconfig
,~/.gitconfig
ou le fichier.git/config
qui se trouve dans le dépôt.
Dans les exemples qui suivent, nous travaillerons sur le niveau global car c'est ce que le développeur souhaite la plupart du temps.
Pour voir, à tout moment, votre configuration :
git config --list
Activer la coloration de la sortie par défaut
[modifier | modifier le wikicode]Par défaut, git doit colorer la sortie de vos commandes sur le terminal. Si ce n'est pas le cas, vous utilisez une version trop ancienne de git.
Vous pouvez toutefois configurer git pour forcer ce comportement par défaut.
git config --global color.ui true
Créer des alias pour vos commandes les plus courantes
[modifier | modifier le wikicode]La création d'alias peut se faire dans le fichier de configuration : vim ~/.gitconfig
.
Les alias sont alors utilisables comme les autres commandes de Git, comme premier argument de la commande git
.
- Exemple pour afficher les logs à un certain format :
[alias]
lg = log --graph --all --decorate
Un alias peut aussi se créer en ligne de commande :
git config --global alias.graph "log --all --decorate --oneline --graph --pretty=format:"%h%x09%an%x09%ad%x09%s""
- Retrouver la branche d'un commit en le plaçant en paramètre $1 (Pull Request). Ex :
git pr 0eccb68
[1] :
[alias]
pr = "!f() { git log --merges --ancestry-path --oneline $1..master | grep 'pull request' | tail -n1 | awk '{ print $5 }'; }; f"
- Ouvrir les fichiers modifiés sur une branche dans un IDE (par exemple pour reprendre le travail après un checkout) :
[alias]
openfiles = !sh -c 'git show --pretty= --name-only | grep / | xargs /opt/PhpStorm-182.4129.45/bin/phpstorm.sh'
Références
[modifier | modifier le wikicode]
Linux
Nous allons maintenant voir comment, lorsque vous travaillez sous Linux, vous pouvez travailler au mieux avec Git et augmenter votre productivité.
Installer un prompt git
[modifier | modifier le wikicode]Si vous travaillez sur un projet plusieurs heures d'affilée, vous avez probablement une console qui reste ouverte en permanence pour commiter régulièrement. Autant éviter de taper « git » à chaque fois, et de passer son temps à faire des « git branch » pour savoir sur quelle branche on travaille.
Pour gagner du temps, vous pouvez installer un prompt git, et pour commencer à travailler, taper
git sh
Cela nous ouvre un prompt git. Désormais, l'invite de commande vous indique le répertoire dans lequel vous vous trouvez mais aussi la branche courante. Toutes les commandes sont automatiquement préfixées par "git", vous pouvez taper directement la commande git à appliquer.
Ctrl+D vous permet de quitter le prompt à tout moment.
Ce shell intègre également beaucoup de raccourcis, consulter git sh --help
pour avoir la liste. Quelques exemples :
# L'espace de travail
a # git add
aa # git add --update (mnémonique « add all »)
stage # git add
ap # git add --patch
p # git diff --cached (mnémonique « patch »)
ps # git diff --cached --stat (mnémonique « patch stat »)
unstage # git reset HEAD
# Commits et historique
ci # git commit --verbose
ca # git commit --verbose --all
amend # git commit --verbose --amend
n # git commit --verbose --amend
k # git cherry-pick
re # git rebase --interactive
pop # git reset --soft HEAD^
peek # git log -p --max-count=1
# Dépôt distant
f # git fetch
pm # git pull (mnemonic: « pull merge »)
pr # git pull --rebase (mnémonique « pull rebase »)
# Divers
d # git diff
ds # git diff --stat (mnémonique « diff stat »)
hard # git reset --hard
soft # git reset --soft
scrap # git checkout HEAD
Si vous tapez dans commande système telles que rm
(pour supprimer un fichier) ou reset
(pour purger l'affichage dans le terminal), ce sera git rm
et git reset
qui seront appelées ! Ce n'est pas ce que vous voulez.
Configurer plusieurs comptes vers la même forge
[modifier | modifier le wikicode]Par exemple pour utiliser un compte Git personnel et un professionnel sur GitLab sur le même PC, cela comporte deux étapes[1] :
- Générer et ajouter les clés SSH sur https://gitlab.com/-/profile/keys (pas rsa car incompatible)
- Ajouter le mapping des clés avec les dépôts avec vim ~/.ssh/config
Windows
Configuration
[modifier | modifier le wikicode]Après installation, trois raccourcis sont accessibles dans le menu démarrer :
- Git Bash : langage Unix.
- Git CMD : langage DOS.
- Git GUI : interface graphique.
Pour que Git se positionne par défaut dans le répertoire de votre choix à chaque ouverture, sous Windows faire un clic droit sur son raccourci, puis modifier le chemin du champ "démarrer dans".
TortoiseGit
[modifier | modifier le wikicode]TortoiseGit est un client pour Git qui permet de gérer ses dépôts depuis l'explorateur Windows.
-
Options
(clic droit d'un dossier) -
Clone
-
Commit
-
Push
La vue des synchronisations permet de consulter la liste des fichiers modifiés (Out ChangeList) avec le différentiel dans chacun si on double-clique dessus (dans une fenêtre TortoiseGitMerge par défaut).
Elle permet aussi d'ouvrir l'option Settings en cliquant sur Manage. Pour enregistrer une connexion dans ces paramètres, cliquer sur le sous-menu de Git appelé Remote (s'il n’apparaît pas, sortir et sélectionner un répertoire avant d'y retourner). L'URL du dépôt peut être de la forme :
- ssh://depot@depot.example.com/home/depot/. Mot de passe à entrer chaque connexion, ou utilisation d'une clé SSH.
- http://depot.example.com/home/depot/. Mot de passe à entrer chaque connexion, ou configuration de netrc[2] over HTTP avec cURL[3].
En cas d'erreurs SSH, se reporter au wikilivre Le système d'exploitation GNU-Linux/Le serveur de shell distant SSH#Problèmes connus.
Une fois installé, le processus TortoiseGit se lance à chaque démarrage et est susceptible de bloquer la suppression de fichiers par l'explorateur.
Modifier les permissions d'un fichier
[modifier | modifier le wikicode]Windows ne gère pas les permissions unix/linux des fichiers, permettant notamment de rendre exécutable un script bash. Cependant, il est possible de modifier les permissions des fichiers au niveau staged de Git, de deux manières différentes. Dans les deux cas, comme tout changement au niveau staged, il faudra ensuite commiter les changements, et potentiellement pousser la modification sur le dépôt distant.
Avec TortoiseGit installé
[modifier | modifier le wikicode]Si TortoiseGit est installé, les permissions sont modifiables dans la boîte de dialogue standard des propriétés du fichier par un clic droit sur le fichier, menu "Propriétés", onglet "Git".
En utilisant Git Bash
[modifier | modifier le wikicode]Dans un terminal Git Bash :
- Changer le répertoire courant pour celui contenant les fichiers dont les permissions doivent être modifiées.
- Entrer la commande suivante pour voir les permissions actuelles :
git ls-files --stage
- Entrer la commande suivante pour modifier les permissions d'un fichier, en les spécifiant avec l'option
--chmod
:git update-index --chmod=+x script.sh
Références
[modifier | modifier le wikicode]
GitLab
GitLab est une forge logicielle open-source lancée en 2011.
Elle fournit une interface graphique pour créer des branches, des tags, des pull requests (appelées merge requests), les relire et les fusionner.
GitLab ne permet pas de créer de nouveaux groupes d'utilisateurs (les quatre possibles sont ceux par défaut), mais on peut inviter une personne sur un dépôt avec un autre groupe que celui qu'elle a ailleurs. Et il gère aussi des groupes d'applications dans lesquels un utilisateur peut avoir les mêmes droits.
CI/CD
[modifier | modifier le wikicode]GitLab CI/CD est un outil d'intégration continue et de déploiement continue[1], fourni avec la forge logicielle Gitlab.
Un pipeline est un ensemble de jobs déclenché automatiquement après différentes actions manuelles (git push, création de merge request, merge de branche, création de tag, ou clique sur le job à lancer).
Ces jobs peuvent être lancés dans un certain ordre ou en parallèle, selon les étapes (stages) auxquelles ils appartiennent.
IHM
[modifier | modifier le wikicode]Dans le menu de gauche de GitLab, cliquer sur :
- "Build" pour voir les tâches qui se lancent sur les serveurs "runners" :
- Pipelines : liste des groupes de jobs déjà lancés sur le dépôt.
- Jobs : liste de tous les jobs.
- Pipeline editor : éditeur en ligne du fichier .gitlab-ci.yml du dépôt. Il s'agit du fichier versionné contenant la configuration des pipelines.
- Pipeline schedules : gestion des tâches planifiées.
- Artifacts
- Settings : accessible uniquement aux propriétaires du repo, pour configurer par exemple les branches protégées ou les conditions de fusion des merge requests.
.gitlab-ci.yml
[modifier | modifier le wikicode]Pour qu'un pipeline se lance par hook dans un dépôt, il doit contenir un fichier .gitlab-ci.yml à la racine.
Exemple simple
[modifier | modifier le wikicode]stages:
- build
build-code:
stage: build
script:
- echo "Hello World!"
- pwd; ls -alh
before_script
[modifier | modifier le wikicode]Script à exécuter avant chaque job.
variables
[modifier | modifier le wikicode]Variables appelables plusieurs fois au sein du .gitlab-ci.yml. Certaines permettent de configurer le comportement de GitLab CI. Exemple :
GIT_STRATEGY
[modifier | modifier le wikicode]Politique de clonage :
- none : pas de clone (ex : si on utilise une image Docker).
- fetch : clone différentiel depuis le dernier.
- clone : clone à partir de zéro[2].
La valeur par défaut est définie dans l'IHM : /settings/ci_cd.
GIT_DEPTH
[modifier | modifier le wikicode]Définit la profondeur lors du clone du dépôt : shallow clone[3].
CI_PIPELINE_SOURCE
[modifier | modifier le wikicode]Origine du pipeline (ex : push, merge, tâche planifiée, clic sur le job...).
Dans un job
[modifier | modifier le wikicode]stage
[modifier | modifier le wikicode]Étape qui lancera le job.
script
[modifier | modifier le wikicode]Script à lancer.
rules
[modifier | modifier le wikicode]Conditions pour déclencher ou interdire le job courant.
Cette clause est préconisée car plus complète, par rapport à "only" et "except" qui servent lister des branches où le job peut s'exécuter ou pas (lors des merges).
dependencies
[modifier | modifier le wikicode]Définit les jobs ont on récupère les artefacts pour le courant.
needs
[modifier | modifier le wikicode]Noms des étapes obligatoires avant.
parallel: matrix
[modifier | modifier le wikicode]Type de needs définissant des jobs à exécuter en parallèle.
parent et child
[modifier | modifier le wikicode]Jobs à exécuter dans un sous-graphe.
include
[modifier | modifier le wikicode]Inclut un .yaml de CI (local ou distant). Ce qui permet par exemple de le construire avant de l'exécuter depuis un autre job.
trigger
[modifier | modifier le wikicode]Pour déclencher une action, par exemple un "include" ou un job d'un autre projet.
Exemple complexe
[modifier | modifier le wikicode]Voici le squelette d'un pipeline complet, dans lequel il faudrait remplacer les echo
par les vraies opérations :
stages:
- build
- test
- publish
- deploy
build:
stage: build
script:
echo 'Build'
except:
refs:
- tags
quality-check:
stage: test
script:
echo 'Quality check'
variables:
GIT_STRATEGY: clone
GIT_DEPTH: 1
tags:
- docker
only:
- branches
except:
refs:
- tags
- master
- develop
run-test:
stage: test
script:
echo 'Tests'
variables:
GIT_STRATEGY: clone
GIT_DEPTH: 1
tags:
- docker
only:
- branches
except:
refs:
- tags
- master
- develop
publish:
stage: publish
script:
echo 'Publish artefact'
variables:
GIT_STRATEGY: none
tags:
- docker
only:
- master
- develop
deploy:
stage: deploy
script:
echo 'Deploy artefact on merge in master'
rules:
- if: $CI_COMMIT_BRANCH == "master"
when: on_success
Debug
[modifier | modifier le wikicode]Vérifier les valeurs des variables[4] :
build-code:
stage: build
script:
- export
Importation
[modifier | modifier le wikicode]Il est possible d'incorporer des tâches de GitLab dans le pipeline, par exemple pour la sécurité :
sast:
before_script: []
stage: test
include:
- template: Security/SAST.gitlab-ci.yml
Déploiements
[modifier | modifier le wikicode]Lancement de tests à chaque Merge Request
[modifier | modifier le wikicode]À chaque Merge Request (alias Pull Request, ou PR, ou MR), un job est créé pour lancer les instructions du .gitlab-ci.yml dans l'ordre. Mais avant de se lancer, il doit attendre la disponibilité d'un serveur de test sur lequel s'exécuter, appelé "runner"[5].
Les runners peuvent être fournis par GitLab ou installés soi-même. Dans ce cas leur configuration se trouve dans un fichier .toml.
Une fois l'évènement GitLab déclenché, la commande pour déployer dépend de l'environnement cible. Par exemple pour Kubernetes, un curl
peut-être utilisé.
À partir d'une image Docker du registre
[modifier | modifier le wikicode]Le principe consiste à envoyer une image Docker dans le registre GitLab pour que les conteneurs puissent l'utiliser ensuite sans avoir à le reconstruire.
$CI_REGISTRY_IMAGE
représente l'URL du registre, ex : https://registry.gitlab.com/mon_espace.
Via Docker
[modifier | modifier le wikicode]image: docker:latest
Via Docker-compose
[modifier | modifier le wikicode]Utile en cas de communication entre plusieurs conteneurs.
image: docker/compose:1.27.4
Via Kaniko
[modifier | modifier le wikicode]Si les conteneurs déployés le sont dans un autre conteneur, cela peut occasionner des problèmes de performances. Kaniko est un système pour éviter cela[6].
image: name: gcr.io/kaniko-project/executor:debug
Références
[modifier | modifier le wikicode]- ↑ https://docs.gitlab.com/ee/ci/
- ↑ https://docs.gitlab.com/ee/ci/runners/configure_runners.html#git-strategy
- ↑ https://docs.gitlab.com/ee/ci/large_repositories/
- ↑ https://docs.gitlab.com/ee/ci/variables/#list-all-environment-variables
- ↑ https://docs.gitlab.com/runner/
- ↑ https://docs.gitlab.com/ee/ci/docker/using_kaniko.html
Voir aussi
[modifier | modifier le wikicode]
GitHub
GitHub est une forge logicielle lancée en 2008, puis rachetée par la société Microsoft en 2018.
Contrairement à GitLab, il ne peut y avoir qu'un seul admin par repo[1], mais on peut créer des groupes d'utilisateurs pour son organisation[2][3]. Donc s'il y a plusieurs mainteneurs de prévu, mieux vaut créer le dépôt dans l'organisation au lieu de le faire dans un profil personnel.
Interface
[modifier | modifier le wikicode]GitHub est utilisable 100 % en ligne, possède aussi un client lourd pour générer des commandes Git.
Dans la vue de comparaison, ajouter "w=1" (white spaces) à l'URL permet de masquer les modifications d'espaces et retours à la ligne.
CI/CD
[modifier | modifier le wikicode]Les pipelines ont été ajoutés en 2019 dans GitHub Actions.
Ils sont configurés en cliquant sur "Actions", et sauvegardés dans des .yml du dossiers .github/worflows/ de l'application.
Exemple simple
[modifier | modifier le wikicode]Pipeline avec deux étapes successives en Python, dans le fichier .github/worflows/python_app.yml :
name: Python application
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Test
run: |
python tests/my_test.py
Migrer de GitHub vers GitLab
[modifier | modifier le wikicode]L'interface graphique de GitLab permet d'importer un dépôt GitHub dont on est admin mais cela ne change pas la configuration des PCs et serveurs qui pointaient vers GitHub.
Pour ce faire, depuis chacun d'eux[4] :
git remote rename origin origin_github git remote add origin https://gitlab.com/mon_organisation/mon_repo # Si besoin de mettre à jour git push -u origin
Références
[modifier | modifier le wikicode]- ↑ Repositories owned by personal accounts have one owner. Ownership permissions can't be shared with another personal account
- ↑ https://github.com/account/organizations/new?plan=free
- ↑ https://docs.github.com/en/organizations/organizing-members-into-teams/creating-a-team
- ↑ https://rtask.thinkr.fr/transform-a-folder-as-git-project-synchronized-on-github-or-gitlab/
Bitbucket
Bitbucket est une forge logicielle de la société Atlassian, lancée en 2008.
CI/CD
[modifier | modifier le wikicode]La configuration des pipelines se trouve dans bitbucket-pipelines.yml.
Un éditeur / validateur en ligne existe sur https://bitbucket-pipelines.atlassian.io/validator.
Les variables spécifiques aux pipelines (qui ne doivent être versionnées dans le dépôt) sont configurables dans l'interface sur /admin/addon/admin/pipelines/repository-variables.
Runners
[modifier | modifier le wikicode]La version gratuite permet de lancer 50 min de pipelines par mois.
Pour éviter cela, on peut lancer les builds sur ses propres serveurs (runners), définis dans /admin/addon/admin/pipelines/runners.
Exemple simple
[modifier | modifier le wikicode]Voici un pipeline avec deux étapes parallèles PHP :
image: composer:latest
pipelines:
default:
- parallel:
- step:
name: UnitTest
script:
- composer install
- bin/phpunit
caches:
- composer
- step:
name: QualityCheck
script:
- composer install
- bin/phpcs
caches:
- composer
Passer de Subversion à Git
Si vous maîtrisez subversion, vous aller sûrement être perturbé dans votre passage à git. En effet, l'écart entre gestion de version centralisée et gestion de version décentralisée est important et ces deux outils ne s'utilisent pas du tout de la même façon même s'il y a des similitudes.
Ce chapitre s'adresse aux personnes qui utilisent subversion et il vise à lever les ambiguité et les confusions qui surgissent quand on découvre git.
Quelques confusions habituelles
[modifier | modifier le wikicode]- Les tags ne sont pas des branches
- Dans subversion, on crée un tag par copie du trunk dans un nouveau dossier qui porte le nom du tag. On recrée ainsi toute l'arborescence du trunk dans un dossier (en fait, une branche puisque c'est une dérivation du tronc) du dépôt. Dans git, les tags ne sont pas des branches. Un tag désigne simplement un commit précis du dépôt.
- L'opération commit n’envoie aucune information vers le dépôt distant
- Dans subversion, commit envoie toutes les modifications réalisées sur votre copie locale vers le dépôt distant. Dans git, commit enregistre les modifications dans votre dépôt local.
- L'opération checkout ne récupère pas un dépôt distant mais change la branche courante.
Équivalences entre les commandes git et les commandes subversion
[modifier | modifier le wikicode]La principale différence entre Git et Subversion (Svn) est que Git possède un dépôt local intermédiaire entre la copie de travail où les fichiers sont modifiables directement et le dépôt distant. Il peut aussi n'y avoir pas de dépôt distant, surtout en début de projet. Cette section suppose qu'un dépôt distant existe, si ce n'est pas le cas, il suffit de ne pas exécuter les commandes le concernant.
Récupérer un dépôt distant
[modifier | modifier le wikicode]Pour Svn, cela crée une copie de travail. Pour Git, cela crée une copie de travail et un dépôt local.
Svn | Git |
---|---|
svn checkout repositoryurl |
git clone repositoryurl |
Soumettre les modifications locales
[modifier | modifier le wikicode]Svn | Git |
---|---|
svn commit -m message |
git add files... |
Mettre à jour son dépôt local / sa copie de travail
[modifier | modifier le wikicode]Svn | Git |
---|---|
svn update |
git pull |
Ressources externes
[modifier | modifier le wikicode]
Travailler avec Git local et un dépôt Subversion distant
Git permet de participer à de nombreux autres systèmes de contrôle de version, comme git-svn
ou git-cvsimport
.
SVN
[modifier | modifier le wikicode]La compatibilité entre Git et Subversion est assurée par git-svn
qui autorise un utilisateur à accéder et participer à un dépôt SVN. Les utilisateurs peuvent générer des patchs locaux pour les envoyer par liste de diffusion, ou soumettre leurs changements aux dépôts d'origine.
Premiers pas
[modifier | modifier le wikicode]Pour commencer à utiliser Git avec des projets sur des serveurs Subversion, il faut créer un dépôt local, et configurer git-svn
:
mkdir projet1
cd projet1
git svn init <URL du dépôt root> -T/chemin/du/tronc
git svn fetch -r <première révision>:HEAD
Le paramètre "première révision" peut être "1", mais pour gagner du temps il est possible de ne prendre que les 10 dernières révisions. svn info
indique alors ces révisions.
Généralement quand on travaille avec des dépôts Subversion, on communique l'URL du projet complète. Pour déterminer l'URL du dépôt racine :
git svn info <URL du dépôt root>
Une ligne du résultat indique le dépôt racine. Le chemin du tronc est simplement le reste de l'URL qui suit.
Il est possible de simplement donner à git-svn
l'URL complète du projet, mais cela peut stopper la possibilité de travailler sur des branches SVN.
Exemples
[modifier | modifier le wikicode]Obtenir Pywikipedia :
$ git svn init http://svn.wikimedia.org/svnroot/pywikipedia/trunk/pywikipedia/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r370 = 318fb412e5d1f1136a92d079f3607ac23bde2c34 (refs/remotes/git-svn)
D treelang_all.py
D treelang.py
W: -empty_dir: treelang.py
W: -empty_dir: treelang_all.py
r371 = e8477f292b077f023e4cebad843e0d36d3765db8 (refs/remotes/git-svn)
D parsepopular.py
W: -empty_dir: parsepopular.py
r372 = 8803111b0411243af419868388fc8c7398e8ab9d (refs/remotes/git-svn)
D getlang.py
W: -empty_dir: getlang.py
r373 = ad935dd0472db28379809f150fcf53678630076c (refs/remotes/git-svn)
A splitwarning.py
...
Récupérer AWB (AutoWikiBrowser) :
$ git svn init svn://svn.code.sf.net/p/autowikibrowser/code/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r15 = 086d4ff454a9ddfac92edb4013ec845f65e14ace (refs/remotes/git-svn)
M AWB/AWB/Main.cs
M AWB/WikiFunctions/WebControl.cs
r16 = 14f49de6b3c984bb8a87900e8be42a6576902a06 (refs/remotes/git-svn)
M AWB/AWB/ExitQuestion.Designer.cs
M AWB/WikiFunctions/GetLists.cs
M AWB/WikiFunctions/Tools.cs
r17 = 8b58f6e5b21c91f0819bea9bc9a8110c2cab540d (refs/remotes/git-svn)
M AWB/AWB/Main.Designer.cs
M AWB/AWB/Main.cs
M AWB/WikiFunctions/GetLists.cs
r18 = 51683925cedb8effb274fadd2417cc9b1f860e3c (refs/remotes/git-svn)
M AWB/AWB/specialFilter.Designer.cs
M AWB/AWB/specialFilter.cs
r19 = 712edb32a20d6d2ab4066acf056f14daa67a9d4b (refs/remotes/git-svn)
M AWB/WikiFunctions/WPEditor.cs
r20 = 3116588b52a8e27e1dc72d25b1981d181d6ba203 (refs/remotes/git-svn)
...
Cette opération de téléchargement peut prendre une heure.
Interagir avec le dépôt
[modifier | modifier le wikicode]L'avantage de travailler avec Git sur des dépôts SVN est l'utilisation en local. Dans ce cas :
- Ne pas lancer
git pull
- Dans une branche mieux vaut éviter de lancer
git-svn dcommit
car les soumissions fusionnées ont tendance à embrouillergit-svn
. Par contre, combiner les changements avec ceux de Subversion en amont est équivalent àsvn update
:
git stash # cache les changements pour obtenir un arbre propre
git svn fetch # amène les derniers changements
git rebase trunk
git stash apply
La première et la dernière ligne ne sont pas nécessaires si l'arbre est propre.
Le git rebase trunk
laisse les soumissions locales au dessus du HEAD SVN[1].
Changements locaux
[modifier | modifier le wikicode]Pour éviter de propager des modifications locales indésirables (débogages, tests...), avec git svn dcommit
, sans les perdre peut passer par deux approches.
Premièrement, maintenir une branche locale pour chacune qui devra contenir des changements locaux. Par exemple faire un rebase
sur "branche1" au-dessus de "branche1-locale". Exemple :
git rebase trunk branche1-locale
git rebase branche1-locale branche1
Deux choix sont ensuite possibles, effectuer directement les changements sur la branche locale, ce qui est plus rapide que de les soumettre à la branche distante avant de les récupérer dans la locale. Ensuite il est possible d'utiliser git reset
[2] pour les retirer de la branche distante.
Comme une alternative à l'approche centrée recombinaison, il existe une méthode basée sur la fusion. Tout en conservant les changements sur une branche locale, mais sans avoir à conserver la branche au dessus de la branche locale par recombinaison.
C'est un avantage car :
- Sinon il y a plus à écrire[précision nécessaire].
- Historiquement, la recombinaison a souvent demandé de résoudre le même conflit deux fois, s'il survient pendant la première recombinaison.
Donc à la place des recombinaisons, on crée une nouvelle branche servant à la construction. Il faut la démarrer avec la soumission à tester. Ensuite git merge
fusionne la branche locale, apportant tous les changements dans un seul arbre. La raison de cette fusion dans une branche reconstruction est pour dissuader l'utilisation de git-svn dcommit
(qui soumettrait les tests indésirables sur le serveur).
Cette approche peut même rendre facultative la recombinaison quotidienne la branche avec le tronc. En cas de branches multiples, les recombinaisons permanentes peuvent s'avérer chronophages :
git checkout build
git reset --hard trunk # s'assurer de l'absence de changement important
git merge branche1 branche1-locale
La construction contient ensuite les changements du tronc, branche1 et branche1-locale !
Il est possible de conserver plusieurs branches locales dont une avec les tests. Cette approche peut être développée avec une branche par sujet dans un arbre :
git merge sujet1 sujet2 config debug...
Malheureusement, la fusion de cette pieuvre ne résout pas les conflits. Dans ce cas il faut appliquer les fusions une par une :
git merge sujet1
git merge sujet1
git merge local
...
Envoyer des changements en amont
[modifier | modifier le wikicode]Éventuellement, pour soumettre au serveur des branches sujet avec un accès commit
, on peut lancer git-svn dcommit
. Cela prendra chaque soumission locale dans la branche courante et le soumettra à subversion. Par exemple avec trois soumissions locales, après dcommit
il y aura trois nouvelles soumissions dans subversion.
Sans accès commit
, le patch devra probablement être soumis via une liste de diffusion ou un logiciel de suivi de problèmes (bug tracker). Pour cela on peut utiliser git-format-patch. Par exemple pour trois soumissions locales :
git format-patch HEAD~3..
Le résultat sera trois fichiers en $PWD, 0001-commit-name.patch, 0002-commit-name.patch, et 0003-commit-name.patch, qui pourront être attachés à des emails ou joint à Bugzilla. Remarque : il existe git-send-email pour envoyer les emails directement :
git send-email *.patch
Si les séries de patchs ne sont pas dans l'ordre, voir git rebase -i
.
Références
[modifier | modifier le wikicode]
Participer au développement de Wikimédia
Prérequis
[modifier | modifier le wikicode]Clé SSH
[modifier | modifier le wikicode]Les soumissions effectuées par Git doivent être authentifiées par Gerrit. Pour ce faire il faut ajouter une clé publique dans son compte https://gerrit.wikimedia.org/r/#/settings/ssh-keys (nommé login dans les exemples ci-dessous).
git-review
[modifier | modifier le wikicode]git-review est un outil en mode ligne de commande pour Git / Gerrit permettant de soumettre une modification, ou de récupérer une modification existante.
apt-get install git-review
ou :
pip install git-review
Site Mediawiki
[modifier | modifier le wikicode]Le dépôt examples.git existe pour s'entraîner.
git review -s
git branch
git remote -v
ssh login@gerrit.wikimedia.org:29418/test/mediawiki/extensions/examples.git
git review -s
git config -l
git config --global user.name "login"
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
git review -sgit pull origin master
git pull origin master
git checkout -b branche-1 master
git diff
git status
git add test1.php
git status
git diff --cached
git commit
git pull origin master
git rebase master
git review -R
cd .git
git fetch https://gerrit.wikimedia.org/r/mediawiki/core refs/changes/69/17069/1 && git checkout FETCH_HEAD
Le fichier test1.php est maintenant présent sur le dépôt de la fondation.
Module quiz
[modifier | modifier le wikicode]cd Git
git clone ssh://login@gerrit.wikimedia.org:29418/mediawiki/extensions/Quiz
cd Quiz
vim Quiz.class.php
git add Quiz.class.php
git commit
git fetch
git push ssh://login@gerrit.wikimedia.org:29418/mediawiki/extensions/Quiz HEAD:refs/for/master
# Error with a change ID
git commit --amend
# Insertion of the change ID at the last line
git push ssh://login@gerrit.wikimedia.org:29418/mediawiki/extensions/Quiz HEAD:refs/for/master
Problèmes connus
Impossible de cloner un dépôt
[modifier | modifier le wikicode]Plusieurs erreurs possibles :
- fatal: Authentication failed for... : l'identifiant de la forge n'est pas le bon.
- Host key verification failed : la clé SSH du dépôt à cloner ne correspond pas à la locale. Par exemple si le clonage a lieu dans un Docker, ce dernier doit avoir accès une clé connue du dépôt (au moyen d'un volume partagé avec l'hôte).
- fatal: Could not read from remote repository / Impossible de lire le dépôt distant : si le git clone est refusé en SSH, essayer en HTTPS. Sinon, créer une clé d'authentification sur le dépôt.
- fatal: repository 'http://MonServeur/MonDepotEnLigne.git' not found / remote: The project you were looking for could not be found or you don't have permission to view it : si le dossier existe et est accessible en HTTP, mais que le
clone
,pull
oupush
ne le trouve pas :- Vérifier que l'utilisateur a les droits d'écriture (pour Windows avec IIS, c'est II_IUSRS).
- Si le dépôt est sur le LAN, éviter HTTP :
git clone file:////MonServeur/c$/inetpub/wwwroot/MonDepotEnLigne.git
. - Dans le cas d'un clone d'un dépôt privé, vous devez faire partie des invités[1].
- Si c'est en SSH, se loguer avant. Ex : ssh -T git@gitlab.com.
- Si cette commande renvoie "error in libcrypto", c'est peut-être que le rsa n'est pas supporté. Auquel cas il faut regénérer une clé par exemple en ed25519.
- Si c'est en HTTP, tester en ajoutant en nom d'utilisateur dans l'URL. Ex : https://mon_login_gitlab@gitlab.com/mon_login_gitlab/mon_repo.git.
- Dans le cas d'un clone de GitHub, ce site n'accepte plus les mots de passe depuis 2022, mais demande à la place un token généré sur https://github.com/settings/tokens.
- Si vous avez deux comptes Git sur la même forge (ex : pro et perso), les ajouter tous les deux dans ~/.ssh/config[2].
Un fichier du .gitignore apparait malgré tout dans ceux à commiter
[modifier | modifier le wikicode]C'est certainement que le fichier avait été commité avant d'être ajouté au .gitignore. Il faut donc le supprimer dans un commit (sans qu'il soit dans .gitignore sinon sa suppression sera ignorée) puis regarder à nouveau s'il apparait. Si c'est le cas le faire disparaitre avec git rm --cached nom_du_fichier
.
Un fichier commité voit ses retours chariot changés à tort
[modifier | modifier le wikicode]git config auto.crlf false
Un fichier ou un dossier n'est pas commité avec les bonnes majuscules
[modifier | modifier le wikicode]Problème propre à Windows :
git config core.ignorecase false
Ne pas changer cette configuration avant de faire un rebase sur une branche créée sans elle, sous peine de ne pas pouvoir rebaser sur les commits de configuration différente.
git reset --hard ne nettoie pas tout
[modifier | modifier le wikicode]git stash -u && git stash clear
cannot checkout in the current repository state
[modifier | modifier le wikicode]Il y a des fichiers créés qui doivent être supprimés ou archivés avant de pouvoir créer une nouvelle branche :
git stash -u
error: droits insuffisant pour ajouter un objet à la base de données .git/objects du dépôt
[modifier | modifier le wikicode]Recloner pour que le dépôt fonctionne.
error: bad index file sha1 signature, fatal: index file corrupt
[modifier | modifier le wikicode]Recloner pour que le dépôt fonctionne (le dépôt a certainement été copié manuellement au lieu d'être cloné).
error: ... Permission denied
[modifier | modifier le wikicode]Un problème de permissions est survenu. Si elles sont bien définies pour le compte utilisé, et que le projet utilise Docker, relancer les conteneurs.
error: could not open '.git/rebased-patches' for reading: Permission denied
[modifier | modifier le wikicode]Erreur lors d'un rebase. Cela peut survenir avec Docker Desktop, dans ce cas :
- Lancer
rebase -i
débloque la situation. - Sinon, lancer le rebase dans un conteneur où le volume du dépôt est partagé.
- Sinon, recréer la branche à partir de celle de base, soit par cherry-pick, soit "stash -u" sur le contenu de la branche à rebaser, la supprimer, puis "stash pop" sur une nouvelle branche du même nom.
- Sinon, remplacer le rebase par un merge.
error: opening .git/config: Permission denied
[modifier | modifier le wikicode]Lors du clonage, au pire on peut télécharger le dépôt.
error: permission denied (publickey)
[modifier | modifier le wikicode]Utiliser HTTPS au lieu de SSH.
Ou initialiser SSH. Ex : ssh -vT git@github.com
.
error: could not restore untracked files from stash
[modifier | modifier le wikicode]Se produit lors d'un git stash pop
ou git stash apply
vers des fichiers en conflit. Pour que le stash les remplace :
git checkout stash --
error: failed to push some refs to ...
[modifier | modifier le wikicode]Il y a plusieurs solutions :
git reset HEAD~1 && git pull && git add -A && git commit -m "Mon commit" && git push
.git pull && git push
: plus simple à faire mais ajoute un merge local pouvant polluer l'historique de la branche.git pull --rebase && git push
: plus propre mais avec risque de conflits.
error: impossible de restaurer les fichiers non-suivis depuis le remisage
[modifier | modifier le wikicode]Forcer l'application du stash avec :
git checkout stash -- .
error: le commit cc636d99b0ac37ba8a5c14a70ce69cb223055deb est une fusion mais l'option -m n'a pas été spécifiée.
[modifier | modifier le wikicode]Pour annuler un merge, il faut rajouter "-m 1" :
git revert -m 1 cc636d99b0ac37ba8a5c14a70ce69cb223055deb
error: pathspec 'MaBranche1' did not match any file(s) known to git
[modifier | modifier le wikicode]Il faut récupérer les nouvelles branches du serveur avec :
git fetch
error: src refspec master does not match any
[modifier | modifier le wikicode]Il faut faire un git add *
avec au moins un changement.
error: The branch 'ma-branche' is not a strict subset of your current HEAD.
[modifier | modifier le wikicode]Voir Git/Branches#Effacer_une_branche.
error: Your local changes to the following files would be overwritten by merge
[modifier | modifier le wikicode]Pour sauvegarder le travail local :
git reset HEAD~1; git stash -u
Pour supprimer le travail local :
git reset --hard
On peut mélanger les deux si on supprime d'abord quelques fichiers avant de sauvegarder le reste :
git checkout src/fichier_a_dropper
failed to create a new commit
[modifier | modifier le wikicode]Reconfigurer :
git config --global user.name "Your Name"
failed to create a pull request
[modifier | modifier le wikicode]Faire un "git push" avant, pour que le serveur connaisse la branche.
failed to push some refs to 'MonDepot1.git' hint: Updates were rejected because the tip of your current branch is behind
[modifier | modifier le wikicode]git push -f 'MonDepot1.git'
voire
git push -f origin
failed to sync this branch because due to unmerged files
[modifier | modifier le wikicode]Le dépôt distant possède certains fichiers qui sont plus à jour que le local, et vice-versa.
Si le message provient d'une interface graphique, essayer de la fermer et de lancer la synchro en shell, avec git push
. Cela peut donner un message plus précis, ex :
remote: error: By default, updating the current branch in a non-bare repository is denied, because it will make the index and work tree inconsistent
Dans ce cas, on peut modifier le fichier "config" du serveur distant en ajoutant "bare=true".
Sinon, il faut créer une nouvelle branche pour faire un "pull request".
Sinon, copier les fichiers locaux dans un autre dossier (parent), et recloner avant de les replacer.
fatal: index-pack failed
[modifier | modifier le wikicode]git pull
n'a pas été lancé depuis le répertoire du dépôt.
fatal: remote origin already exists
[modifier | modifier le wikicode]Pour redéfinir origin
il faut le supprimer d'abord :
git remote rm origin
fatal: This operation must be run in a work tree
[modifier | modifier le wikicode]Lors d'un git add
sur un dépôt initialisé avec -- bare
, il faut soit uniquement lui soumettre ses modifications (sans possibilité de le cloner, avec git remote add origin
[3]), soit définir un répertoire de branche avec --work-tree
.
fatal: unable to access 'https://MonServeur/MonDepotEnLigne.git/': SSL certificate problem: self signed certificate
[modifier | modifier le wikicode]Lors du clonage, remplacer HTTPS par HTTP, ou bien désactiver la vérification du certificat SSL :
git -c http.sslVerify=false clone https://MonServeur/MonDepotEnLigne.git
File mode changed from 100644 to 100755
[modifier | modifier le wikicode]Si certains fichiers apparaissent dans les diff car leurs métadonnées ont été modifiées (et pas leur contenu), c'est qu'une application a changé leurs inodes. Pour éviter cela :
git config core.filemode false
Please, commit your changes or stash them before you can merge
[modifier | modifier le wikicode]Précéder le pull
d'un stash
:
git stash
git pull
This file is empty
[modifier | modifier le wikicode]Si un fichier apparait comme modifié, mais que son diff affiche ce message, c'est que seules ses métadonnées ont changé (ex : date de mise à jour).
warning: LF will be replaced by CRLF
[modifier | modifier le wikicode]git config --global core.autocrlf true
You must edit all merge conflicts and then mark them as resolved using git add
[modifier | modifier le wikicode]Survient lors d'un :
git rebase --continue
non précédé d'un :
git add -A
Bien sûr les fichiers en conflit doivent faire partie de cet ajout.
you need to resolve your current index first
[modifier | modifier le wikicode]git reset --merge
Cela sert aussi à annuler un merge demandé par "git stash pop".
Your branch is behind 'xxx' by y commits, and can be fast-forwarded
[modifier | modifier le wikicode]Dans ce cas il peut être préférable d'effacer la veille branche du serveur pour ne garder que la locale, qui sera synchronisée sur le serveur ensuite.
Références
[modifier | modifier le wikicode]
Ressources externes
Guides pour démarrer
[modifier | modifier le wikicode]Documentations
[modifier | modifier le wikicode]- La documentation officielle
- Le livre Pro Git
- Git Magic montre énormément de choses inattendues que l'on peut faire avec git
- Une documentation proposée sur le site d'Atlassian qui est en français et qui propose notamment une partie consacrée au différents workflows Git
- Beaucoup d'astuces dans la page consacrée à Git du wiki de kernel.org
Aide-mémoires
[modifier | modifier le wikicode]Il n'est pas évident de se souvenir des toutes les commandes git. Aussi, il peut vous être utile d'avoir, sous la main, un aide-mémoire dédié :
- une fiche réalisée par l'équipe GitHub (format 2 × A4)
- une référence rapide interactive, elle est organisée selon le niveau où on souhaite travailler (stash, index, remote...). Elle a l'avantage d'être disponible en français.
Vidéos
[modifier | modifier le wikicode]Extensions git pour le développeur
[modifier | modifier le wikicode]- git-extras est une extension qui se propose d'ajouter des commandes à git pour faire quelques manipulation récurrentes.
Outils de visualisation des dépôts git
[modifier | modifier le wikicode]Une liste d'outils qui peuvent représenter des alternatives intéressantes à gitweb qui est livré par défaut :
Certains projets ont pour objectif d'être des alternatives open-source à GitHub :
Enfin, gerrit est un outil spécialisé pour la revue de code.
GFDL | Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture. |